Reputation: 2061
I have the following SQL Query that counts Orders and groups them by each Day (Date).
Thus the following results:
01/02/2014 = 10
02/02/2014 = 2
05/02/2014 = 7
07/02/2014 = 4
Query:
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
My question is, how can I get my Query to fill in any of the in-between missing dates and set the Count value to 0?
Example Desired Results:
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
Many thanks for you time taken out to read this.
Upvotes: 0
Views: 3210
Reputation: 2753
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 is written to generate all dates in a date range. With this a LEFT JOIN
of aggregation resultset is done.
Disclaimer: this query would not work if the date range is more that 32767 days
Upvotes: 3
Reputation: 92845
If you issue a lot of such queries then you can create a calendar table that contain all calendar dates
CREATE TABLE calendar([date] DATE NOT NULL PRIMARY KEY);
And then use an outer join
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
Output:
| 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 |
Here is SQLFiddle demo
Upvotes: 1
Reputation:
You could do something along the lines of this. I've not tested it thoroughly but in principle if you're unioning it'll ditch extras. You may need to do an order on the output to put it in the right order
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]
Is it possible that you know the start and end date that you could pass in as seed dates?
Upvotes: 0