This query pulls counts for every hour of every day but leaves off any days and hours that don’t have counts. How can I fill in the missing dates and hours between the dates selected with 0 for the counts?
SELECT CAST(RecordTime AS date) AS Date, DATENAME(dw, RecordTime) AS [Day of the week], DATEPART(hour, RecordTime) AS [Hour of the day], COUNT(*) AS [Hourly Count]
FROM Counts
WHERE (RecordTime >= CONVERT(DATETIME, '2022-04-01 00:00:00', 102)) AND (RecordTime < CONVERT(DATETIME, '2022-05-01 00:00:00', 102)) AND (MachineNum = 11) AND (Cavity = 1)
GROUP BY CAST(RecordTime AS date), DATEPART(hour, RecordTime), DATENAME(dw, RecordTime)
ORDER BY Date, [Hour of the day]
>Solution :
As Larnu suggested, you need to generate a full dataset with all day+hour combinations in the range, in order to left join to. By my calculation you need 30 days * 24 hours = 720 rows. If you don’t already have a numbers table, or a calendar table, or a sequence generating function, you can generate this using recursive CTEs as follows:
DECLARE @StartDate datetime = '20220401',
@AfterLastDate datetime = '20220501';
;WITH days(d) AS
(
SELECT 0 UNION ALL SELECT d+1 FROM days
WHERE d < DATEDIFF(DAY, @StartDate, @AfterLastDate) - 1
), hours(h) AS
(
SELECT 0 UNION ALL SELECT h+1 FROM hours WHERE h<23
),
dates(DayHour, h) AS
(
SELECT DATEADD(HOUR, hours.h, DATEADD(DAY, days.d, @StartDate)), hours.h
FROM days CROSS JOIN hours
)
SELECT d.DayHour, DATENAME(WEEKDAY, DayHour), d.h
FROM dates AS d
ORDER BY d.DayHour;
Output:
DayHour Day of the week Hour of the day 2022-04-01 00:00:00.000 Friday 0 2022-04-01 01:00:00.000 Friday 1 2022-04-01 02:00:00.000 Friday 2 … 714 more rows … 2022-04-30 21:00:00.000 Saturday 21 2022-04-30 22:00:00.000 Saturday 22 2022-04-30 23:00:00.000 Saturday 23
- Example db<>fiddle
Now, we just need to left outer join that against your existing table:
DECLARE @StartDate datetime = '20220401',
@AfterLastDate datetime = '20220501';
;WITH days(d) AS
(
SELECT 0 UNION ALL SELECT d+1 FROM days
WHERE d < DATEDIFF(DAY, @StartDate, @AfterLastDate) - 1
), hours(h) AS
(
SELECT 0 UNION ALL SELECT h+1 FROM hours WHERE h<23
),
dates(DayHour, h) AS
(
SELECT DATEADD(HOUR, hours.h, DATEADD(DAY, days.d, @StartDate)),
hours.h FROM days CROSS JOIN hours
)
SELECT [Date] = CONVERT(date, d.DayHour),
[Day of the week] = DATENAME(WEEKDAY, d.DayHour),
[Hour of the day] = d.h,
[Hourly Count] = COUNT(c.RecordTime)
FROM dates AS d
LEFT OUTER JOIN dbo.Counts AS c
ON c.RecordTime >= d.DayHour
AND c.RecordTime < DATEADD(HOUR, 1, d.DayHour)
AND c.MachineNum = 11
AND c.Cavity = 1
GROUP BY CONVERT(date, d.DayHour), DATENAME(WEEKDAY, DayHour), d.h
ORDER BY [Date], [Hour of the day];
- Example db<>fiddle