SQL Server:即使某些天没有数据,如何选择日期范围内的所有日期

Ale*_*lex 28 t-sql sql-server

我有一个应用程序需要显示过去30天内的活动条形图.即使当天没有任何活动,图表也需要显示所有日期.

例如:

DATE       COUNT
==================
1/1/2011   5 
1/2/2011   3 
1/3/2011   0
1/4/2011   4
1/5/2011   0
etc....
Run Code Online (Sandbox Code Playgroud)

我可以在查询之后进行后期处理以找出缺少的日期并添加它们但是想知道在SQL Server中是否有更简单的方法.非常感谢

Ale*_* K. 35

您可以使用递归CTE来构建30天的列表,然后将其加入到您的数据中

--test
select cast('05 jan 2011' as datetime) as DT, 1 as val into #t
union all select CAST('05 jan 2011' as datetime), 1 
union all select CAST('29 jan 2011' as datetime), 1 

declare @start datetime = '01 jan 2011'
declare @end   datetime = dateadd(day, 29, @start)

;with amonth(day) as
(
    select @start as day
        union all
    select day + 1
        from amonth
        where day < @end
)
select amonth.day, count(val)
    from amonth 
    left join #t on #t.DT = amonth.day
group by amonth.day


>>

2011-01-04 00:00:00.000 0
2011-01-05 00:00:00.000 2
2011-01-06 00:00:00.000 0
2011-01-07 00:00:00.000 0
2011-01-08 00:00:00.000 0
2011-01-09 00:00:00.000 0
...
Run Code Online (Sandbox Code Playgroud)

  • 如果天数大于100,则不起作用.我得到错误"最大递归深度为100".是的,答案回答了问题,但可能导致错误. (4认同)
  • 那么你的问题与OP中的问题不同,它有一个绝对的30项窗口,这个解决方案很好并且不会出错.如果你想增加递归限制,只需告诉它这样做; `选项(maxrecursion 100)` (4认同)
  • +1用于使用递归CTE来获取一组值. (2认同)

Ian*_*ley 9

使用CTE:

WITH DateTable
AS
(
    SELECT CAST('20110101' AS Date) AS [DATE]
    UNION ALL
    SELECT DATEADD(dd, 1, [DATE])
    FROM DateTable
    WHERE DATEADD(dd, 1, [DATE]) < cast('20110201' as Date)
)
SELECT dt.[DATE], ISNULL(md.[COUNT], 0) as [COUNT]
FROM [DateTable] dt
LEFT JOIN [MyData] md
ON md.[DATE] = dt.[DATE]
Run Code Online (Sandbox Code Playgroud)

这假设一切都是日期; 如果它是DateTime,你将不得不截断(with DATEADD(dd, 0, DATEDIFF(dd, 0, [DATE]))).


ped*_*iri 5

@Alex K. 的答案是完全正确的,但它不适用于不支持递归公用表表达式的版本(例如我正在使用的版本)。在这种情况下,以下将完成这项工作。

DECLARE @StartDate datetime = '2015-01-01'
DECLARE @EndDate datetime = SYSDATETIME()

;WITH days AS
(
  SELECT DATEADD(DAY, n, DATEADD(DAY, DATEDIFF(DAY, 0, @StartDate), 0)) as d
    FROM ( SELECT TOP (DATEDIFF(DAY, @StartDate, @EndDate) + 1)
            n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
           FROM sys.all_objects ORDER BY [object_id] ) AS n
)
select days.d, count(t.val)
    FROM days LEFT OUTER JOIN yourTable as t
    ON t.dateColumn >= days.d AND t.dateColumn < DATEADD(DAY, 1, days.d)
GROUP BY days.d
ORDER BY days.d;
Run Code Online (Sandbox Code Playgroud)