You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server获取两日期区间全部日期 除左连临时日历表有其他方法吗

SQL Server补全报表日期区间的优化方案

你当前使用WHILE循环逐行插入临时表生成日期的方案,在日期跨度较大时性能损耗很高,以下是三种更优的实现方案,可根据使用场景选择:


方案1:递归CTE动态生成日期序列(无需预建表,适合临时查询)

无需提前创建临时表,单次查询直接生成目标日期区间,性能远高于循环插入,代码轻量化。

DECLARE @startDate DATE = '2021-09-05', @endDate DATE = '2021-09-15';

WITH calendarCTE AS (
    SELECT @startDate AS calendarDate
    UNION ALL
    SELECT DATEADD(DAY, 1, calendarDate)
    FROM calendarCTE
    WHERE calendarDate < @endDate
)
SELECT *
FROM calendarCTE td
LEFT JOIN dataTable dt WITH (NOLOCK) ON dt.reportDate = td.calendarDate
-- 日期跨度超过100天时必须加以下配置取消递归深度限制
OPTION (MAXRECURSION 0);

方案2:永久日历维度表(适合生产环境高频查询场景)

如果业务中频繁需要生成跨日期报表,建议一次创建永久日历表,终身复用,还可扩展多维度日期属性,性能是所有方案中最优的。

建表&初始化代码(仅执行一次)

-- 创建日历维度表
CREATE TABLE dimCalendar (
    calendarDate DATE PRIMARY KEY,
    year INT,
    month INT,
    day INT,
    weekOfYear INT,
    isWeekend BIT
    -- 可按需扩展是否节假日、所属季度等属性
);

-- 批量初始化100年日期
DECLARE @start DATE = '2020-01-01', @end DATE = '2119-12-31';
WITH calendarCTE AS (
    SELECT @start AS calendarDate
    UNION ALL
    SELECT DATEADD(DAY, 1, calendarDate)
    FROM calendarCTE
    WHERE calendarDate < @end
)
INSERT INTO dimCalendar (calendarDate, year, month, day, weekOfYear, isWeekend)
SELECT 
    calendarDate,
    YEAR(calendarDate),
    MONTH(calendarDate),
    DAY(calendarDate),
    DATEPART(WEEK, calendarDate),
    CASE WHEN DATEPART(WEEKDAY, calendarDate) IN (1,7) THEN 1 ELSE 0 END
FROM calendarCTE
OPTION (MAXRECURSION 0);

后续查询代码

SELECT *
FROM dimCalendar td WITH (NOLOCK)
LEFT JOIN dataTable dt WITH (NOLOCK) ON dt.reportDate = td.calendarDate
WHERE td.calendarDate BETWEEN '2021-09-05' AND '2021-09-15';

方案3:数字辅助表生成日期(适合大跨度日期动态查询)

如果不想维护永久日历表,又需要频繁生成大跨度日期序列,可提前创建数字辅助表,生成日期的性能高于递归CTE,无递归深度限制。

建数字辅助表(仅执行一次)

-- 存储0~100000的数字,可覆盖超过270年的日期跨度
CREATE TABLE nums (n INT PRIMARY KEY);
WITH t1 AS (SELECT 1 n UNION ALL SELECT 1),
t2 AS (SELECT 1 n FROM t1 a, t1 b),
t3 AS (SELECT 1 n FROM t2 a, t2 b),
t4 AS (SELECT 1 n FROM t3 a, t3 b),
t5 AS (SELECT 1 n FROM t4 a, t4 b),
numsCTE AS (SELECT ROW_NUMBER() OVER(ORDER BY n) -1 AS n FROM t5)
INSERT INTO nums SELECT n FROM numsCTE WHERE n <= 100000;

查询代码

DECLARE @startDate DATE = '2021-09-05', @endDate DATE = '2021-09-15';
SELECT *
FROM (
    SELECT DATEADD(DAY, n, @startDate) AS calendarDate
    FROM nums
    WHERE n <= DATEDIFF(DAY, @startDate, @endDate)
) td
LEFT JOIN dataTable dt WITH (NOLOCK) ON dt.reportDate = td.calendarDate;

方案选择建议

  • 临时单次查询、日期跨度小于1000天:选递归CTE方案,无需预建任何表
  • 生产环境高频生成日期类报表:选永久日历表方案,性能最优、扩展性最强
  • 无永久表维护权限、经常查询大跨度日期:选数字辅助表方案

内容的提问来源于stack exchange,提问作者user2046734

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 00:15:01