订购日期为 4 周

Ordering dates for 4 weeks

我正在编写一个 SQL 查询,用于提取过去 4 周的一些信息。 我发现我的结果有两个问题(见下文)。

第一个问题是我回头看四个星期,范围应该是8月10日-9月6日。当我在'Day of the Month'之前订购时,日期是9月当它们实际上应该在最后时被移动到结果的顶部。所以我的结果应该从 10 点(8 月)开始,到 6 点(9 月)结束。

第二个问题 是我遗漏了一些随机日期(3、4、13、27)。

Day of the Month    Number of X
1                   125
2                   77
5                   5
6                   23
10                  145
11                  177
12                  116
14                  2
15                  199
16                  154
17                  134
18                  140
19                  154
21                  8
22                  166
23                  145
24                  151
25                  107
26                  79
28                  3
29                  151
30                  163
31                  147

这是我查询的一般版本:

DECLARE @startDate datetime, @endDate datetime;
SET @startDate = dateadd(day, -28, GETDATE());
SET @endDate = dateadd(day, -1, GETDATE());

Select DATEPArt(dd, Time) AS 'Day of the Month', count(*) AS ' Number of X' 
from SomeTable ST
where Time >= @startDate
AND Time <  @endDate 
group by DATEPArt(dd, Time)   
order by 'Day of the Month'  

对于第一个问题,您可以按日期排序以获得正确的日期顺序。我使用 convert 来获取无时间日期,以便条目正确分组。

DECLARE @StartDate datetime, @EndDate datetime;
SET @StartDate = DATEADD(day, -28, GETDATE());
SET @EndDate = DATEADD(day, -1, GETDATE());

SELECT 
DATEPART(dd, Convert(date, Time)) AS 'Day of the Month', COUNT(*) AS ' Number of X' 
FROM SomeTable ST
WHERE Time >= @StartDate
AND Time <  @EndDate 
GROUP BY Convert(date, Time) 
ORDER BY Convert(date, Time) 

至于缺失的天数,这更复杂,因为分组依据需要有数据才能工作。

一个选项是创建一个包含所有日期的临时 table,然后加入数据。这仍然会留下一行,其中连接没有找到任何数据,并且可以获得 "zero" 计数。

DECLARE @StartDate datetime, @EndDate datetime;
SET @StartDate = DATEADD(day, -28, GETDATE());
SET @EndDate = DATEADD(day, -1, GETDATE());

--Create temporary table with all days between the two dates
;WITH d(d) AS 
(
  SELECT DATEADD(DAY, n, DATEADD(DAY, DATEDIFF(DAY, 0, @StartDate), 0))
  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
)
--Join in our query to the table temporary table
SELECT  
    DATEPART(dd, d.d) AS 'Day of the Month', 
    COUNT(Time) AS ' Number of X' 
FROM d LEFT OUTER JOIN SomeTable ST ON DATEPART(dd, d.d) = DATEPART(dd, Time) 
                              AND Time >= @StartDate 
                              AND Time <  @EndDate 
GROUP BY d.d
ORDER BY d.d