2014-02-06 45 views
0

我有以下SQL查询计数订单,并按每个日期(日期)进行分组。SQL计数记录,按日期分组并填写缺失日期?

因此,下面的结果:

01/02/2014 = 10 
02/02/2014 = 2 
05/02/2014 = 7 
07/02/2014 = 4 

查询:

SELECT TOP(@NumberOfRecords) DATEADD(dd, 0, DATEDIFF(dd, 0, AddedDate)) AS Date,  COUNT(DISTINCT ID) AS Count 
      FROM OrderSpecs 
      GROUP BY DATEADD(dd, 0, DATEDIFF(dd, 0, AddedDate)) 
      ORDER BY Date DESC 

我的问题是,怎样才能让我的查询填写任何在两者之间缺少的日期,并设置计数值为0?

例期望的结果:

01/02/2014 = 10 
    02/02/2014 = 2 
    03/02/2014 = 0 
    04/02/2014 = 0 
    05/02/2014 = 7 
    06/02/2014 = 0 
    07/02/2014 = 4 

你取出时间阅读本非常感谢。

回答

1
DECLARE @mindate DATETIME 
DECLARE @maxdate DATETIME 
DECLARE @diff INT 
SELECT @maxdate = MAX(addeddate), @mindate = MIN(addeddate) FROM OrderSpecs 
SET @diff = DATEDIFF(DAY, @mindate,@maxdate) 
;WITH cte(dt,level) 
AS 
(
    SELECT @mindate AS dt, 0 AS level 
    UNION ALL 
    SELECT DATEADD(day,1,cte.dt),level + 1 from cte WHERE level < @diff 
) 
SELECT dt,c FROM cte 
LEFT JOIN 
(
    SELECT DATEADD(dd, 0, DATEDIFF(dd, 0,AddedDate)) AddedDt, COUNT(ID) AS c 
    FROM OrderSpecs 
    GROUP BY DATEADD(dd, 0, DATEDIFF(dd, 0,AddedDate)) 
) tab 
ON cte.dt = tab.AddedDt 
OPTION (MaxRecursion 32767); 

CTE被写入来生成日期范围内的所有日期。通过这个聚合结果集的LEFT JOIN完成。

免责声明:如果日期范围是更多的32767天

+0

谢谢你,我真的很感激你回到我身边。一个问题是,dt列正在返回第一个日期记录的时间部分并将其应用于所有其他日期。即** 20/12/2013 14:42:56 **,那么下一个记录是** 21/12/2013 14:42:56 **。您填写空白日期的解决方案正在运行,但是,第一个项返回时,所有计数结果为空,第一个计数结果项为1.我要查找的结果应该是** Date:20/12/2013 Count :4 **,**日期:21/12/2013计数:0 **,**日期:22/12/2013计数:7 **。 – RobHurd

+0

已根据您的意见对我的答案进行了一些修改。解决方案是假设AddedDate是日期字段,但实际上它是一个日期时间字段,我想这是意想不到的结果。让我知道编辑工作与否! –

+0

谢谢修改Dipendu保罗。我真的很感谢你的帮助。最初你的修正案没有奏效,但是我编辑了** DECLARE mindate DATETIME **&** DECLARE maxdate DATETIME **到** DATE **,现在它看起来像预期的那样工作。我需要更彻底地检查返回的结果,但在表面上看起来工作得很好。我无法对你的帮助表示感谢。 – RobHurd

0

你可以沿着这条线做些事情。我没有对它进行彻底的测试,但是原则上,如果你正在组织工会,它会抛出额外的费用。您可能需要对输出做一个为了把它放在正确的顺序

SELECT SS1.Date, Count 
FROM 
( 
DECLARE @mindate Date 
DECLARE @maxdate Date 
WITH DateTable 
AS 
(
    SELECT CAST(@mindate as Date) AS [DATE] 
    UNION ALL 
    SELECT DATEADD(dd, 1, [DATE]) FROM DateTable 
    WHERE DATEADD(dd, 1, [DATE]) BETWEEN @mindate AND @maxdate 
) 
SELECT dt.[DATE], 0 [Count] FROM [DateTable] dt 
UNION ALL 

TOP(@NumberOfRecords) DATEADD(dd, 0, DATEDIFF(dd, 0, AddedDate)) AS Date,   COUNT(DISTINCT ID) AS Count 
     FROM OrderSpecs 
     GROUP BY DATEADD(dd, 0, DATEDIFF(dd, 0, AddedDate)) 
     ORDER BY Date DESC 
) SS1 
ORDER BY [Date] 

难道你知道你可以传递作为种子日期开始和结束日期?

+0

我收到此错误'终止声明此查询是行不通的。在声明完成之前,最大递归100已经用完了。 –

+0

您的日期范围有多宽?我的猜测是超过100天? - 虽然,我喜欢@peterm解决方案更多 – owen79

+0

它是120天宽 –

2

如果发出了很多这样的疑问,那么你可以创建一个包含所有日历日期

CREATE TABLE calendar([date] DATE NOT NULL PRIMARY KEY); 

日历表,然后使用外连接

SELECT TOP(@NumberOfRecords) 
     c.Date, COALESCE(o.Count, 0) Count 
    FROM Calendar c LEFT JOIN 
(
    SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, AddedDate)) AS Date, 
     COUNT(DISTINCT ID) AS Count 
    FROM OrderSpecs 
    GROUP BY DATEADD(dd, 0, DATEDIFF(dd, 0, AddedDate)) 
) o 
    ON c.Date = o.Date 
ORDER BY Date DESC 

输出:

 
|  DATE | COUNT | 
|------------|-------| 
| 2014-02-07 |  4 | 
| 2014-02-06 |  0 | 
| 2014-02-05 |  7 | 
| 2014-02-04 |  0 | 
| 2014-02-03 |  0 | 
| 2014-02-02 |  2 | 
| 2014-02-01 | 10 | 

这里是SQLFiddle d emo

+0

感谢您回到我身边,我感谢您提供您的解决方案。我不是特别想要创建一个充满日期的表的路线。但我明白你来自哪里。 – RobHurd

+0

@RobHurd你很受欢迎。只要确保您在生产中获得最佳性能。 – peterm