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

如何在SQL Server存储过程中显示当月所有日期(含无记录日期)

解决SQL Server中生成当月全日期报表的问题

这问题我日常开发中经常碰到——核心原因是你现在的查询是以业务表(table1)作为主表,但业务表只有存在数据的日期记录,所以左关联后自然不会显示无数据的日期。要实现全日期输出,你需要先构造一个包含当月所有日期的日期维度数据集,再以此为基础左关联业务表。

方法一:用递归CTE生成临时日期范围(最方便,无需额外表)

递归CTE是SQL Server里生成连续日期的常用方式,不需要预先创建任何辅助表,直接在查询里生成:

DECLARE @FromDate DATE = '2020-01-01';
DECLARE @ToDate DATE = '2020-01-31';

-- 第一步:生成当月所有日期的临时数据集
WITH DateRange AS (
    SELECT @FromDate AS ReportDate  -- 起始日期
    UNION ALL
    SELECT DATEADD(DAY, 1, ReportDate)  -- 逐天递增
    FROM DateRange
    WHERE ReportDate < @ToDate  -- 直到达到结束日期
)
-- 第二步:以日期维度为主表,左关联业务表
SELECT 
    dr.ReportDate,  -- 保证输出每个日期
    a1.f1, 
    a1.f2, 
    b.f3, 
    b.f5 
FROM DateRange dr
LEFT JOIN table1 a1 
    ON a1.Date = dr.ReportDate  -- 关联业务表的日期到报表日期
LEFT JOIN table2 b 
    ON b.f1 = a1.f1 
    AND b.Date = dr.ReportDate  -- 如果table2也有日期字段,务必关联,避免重复数据
OPTION (MAXRECURSION 0);  -- 解除递归次数限制(默认100,当月31天没问题,大日期范围必须加)

方法二:用数字表生成日期(效率更高,适合大日期范围)

如果你有一个预先创建的Numbers表(包含连续数字1到N),可以用这种方式生成日期,性能比递归CTE更好:

DECLARE @FromDate DATE = '2020-01-01';
DECLARE @ToDate DATE = '2020-01-31';

-- 用Numbers表生成日期范围
WITH DateRange AS (
    SELECT DATEADD(DAY, n.Number - 1, @FromDate) AS ReportDate
    FROM Numbers n
    WHERE DATEADD(DAY, n.Number - 1, @FromDate) <= @ToDate
)
-- 关联业务表的逻辑和上面一致
SELECT 
    dr.ReportDate,
    a1.f1, 
    a1.f2, 
    b.f3, 
    b.f5 
FROM DateRange dr
LEFT JOIN table1 a1 
    ON a1.Date = dr.ReportDate
LEFT JOIN table2 b 
    ON b.f1 = a1.f1 
    AND b.Date = dr.ReportDate;

关键注意点

  • 主表必须是日期维度:只有把全日期的数据集作为主表,才能保证所有日期都被输出,无数据的字段自动显示NULL。
  • 关联条件要精准:业务表和日期维度的关联必须基于日期字段,否则会出现数据匹配错误或重复。
  • 递归CTE的MAXRECURSION:如果你的日期范围超过100天,一定要加上OPTION (MAXRECURSION 0),否则会触发递归次数超限的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 00:02:48