Reputation: 741
I'm using SQL Server 2008 R2.
I’m querying a table of Hospital Appointment Slots and trying to return a list of how many appointment slots for a specific doctor are flagged as being booked, grouped by week number/year.
There are some instances of weeks that don’t have any booked appointments yet, but I want the result to list ALL the forthcoming weeks, even where the count of booked appointment slots is zero.
The output I’m looking for is along these lines:
-------------------------------------------
Year | Week Number | Number of Booked Slots
-------------------------------------------
2017 | 48 | 10
2017 | 49 | 0
2017 | 50 | 4
2017 | 51 | 2
2017 | 52 | 0
2018 | 1 | 5
I understand that a standard select aggregating the results won’t show those weeks where there's a zero count of records, because there’s nothing to return – so I’ve tried to get around this by using a cte to first produce a list of all the forthcoming weeks.
However, try as I might, I can’t get the query to display the zero weeks...
I’ve seen a number of solutions to similar problems to this, but despite experimenting I haven’t been able to apply them to my particular problem (including SQL Count to include zero values)
This is the latest iteration of the query I’ve written so far.
WITH CTE_Dates AS
(
SELECT DISTINCT Slot_Start_Date AS cte_date
FROM [Outpatients.vw_OP_Clinic_Slots WITH (NOLOCK)
)
SELECT
DATEPART(year,OPCS.Slot_Start_Date) [Year]
,DATEPART(week,OPCS.Slot_Start_Date) [Week Number]
,count(OPCS.Slot_Start_Date) [Number of Booked Slots]
FROM
Outpatients.vw_OP_Clinic_Slots OPCS WITH (NOLOCK)
LEFT OUTER JOIN CTE_Dates ON OPCS.Slot_Start_Date=CTE_Dates.cte_date
LEFT OUTER JOIN Outpatients.vw_OP_Clinics CLIN ON OPCS.Clinic_Code=CLIN.Clinic_Code
WHERE
OPCS.Slot_Start_Date >= '14/08/2017'
AND OPCS.Booked_Flag = 'Y'
AND CLIN.Lead_Healthcare_Professional_Name = 'Dr X'
GROUP BY
DATEPART(year,OPCS.Slot_Start_Date)
,DATEPART(week,OPCS.Slot_Start_Date)
ORDER BY
DATEPART(year,OPCS.Slot_Start_Date)asc
,DATEPART(week,OPCS.Slot_Start_Date)asc
The result it’s returning me is correct, BUT I just need it to include those weeks in the list where the count is zero.
Please can anyone explain where I’m going wrong? I’m guessing I’m not joining the cte correctly, but I’ve tried both right and left joins which produce the same result. I’ve also tried inverting the query by swopping the above query statement and cte around, but this doesn’t work either.
Appreciate any guidance anyone can suggest.
Upvotes: 3
Views: 274
Reputation: 194
IF OBJECT_ID(N'tempdb..##cal_weeks_temp', N'U') IS NOT NULL
DROP TABLE ##cal_weeks_temp;
create table ##cal_weeks_temp (date_of_week date, week_num int)
declare @start_date date
declare @end_date date
set @start_date='01/01/2017'
set @end_date='12/31/2018'
while @start_date<@end_date
begin
set @start_date=dateadd(day,1,@start_date)
insert into ##cal_weeks_temp values (@start_date,DATEPART(week,@start_date))
end
select YEAR(t1.date_of_week) 'YEAR',t1.week_num,
sum(case convert(varchar,t2.BookedTime,105) when convert(varchar,t1.date_of_week,105) then 1 else 0 end) 'count'
from ##cal_weeks_temp t1
left join Your_Table t2
on convert(varchar,t2.BookedTime,105)=convert(varchar,t1.date_of_week,105)
group by YEAR(t1.date_of_week) ,t1.week_num
order by YEAR(t1.date_of_week) ,t1.week_num
Upvotes: 0
Reputation: 2798
Just RIGHT JOIN
@ListOfWeeks
table to the result set you have:
DECLARE @ListOfWeeks TABLE ([Week_No] int, [Year_Number] int);
DECLARE @i tinyint = 1, @y int = 2010;
WHILE @i <= 52 AND @y < 2018
BEGIN
INSERT INTO @ListOfWeeks([Week_No], [Year_Number]) VALUES (@i, @y);
IF @i = 52 BEGIN
SET @i = 0
SET @y +=1
END
SET @i += 1
END
SELECT * FROM @ListOfWeeks
WITH [Your_Part] AS(
SELECT
DATEPART(year,OPCS.Slot_Start_Date) [Year]
,DATEPART(week,OPCS.Slot_Start_Date) [Week Number]
,count(OPCS.Slot_Start_Date) [Number of Booked Slots]
FROM
Outpatients.vw_OP_Clinic_Slots OPCS WITH (NOLOCK)
LEFT OUTER JOIN CTE_Dates ON OPCS.Slot_Start_Date=CTE_Dates.cte_date
LEFT OUTER JOIN Outpatients.vw_OP_Clinics CLIN ON OPCS.Clinic_Code=CLIN.Clinic_Code
WHERE
OPCS.Slot_Start_Date >= '14/08/2017'
AND OPCS.Booked_Flag = 'Y'
AND CLIN.Lead_Healthcare_Professional_Name = 'Dr X'
GROUP BY
DATEPART(year,OPCS.Slot_Start_Date)
,DATEPART(week,OPCS.Slot_Start_Date)
),
SELECT xxx.[Year_Number], xxx.[Week_No], yp.[Number of Booked Slots]
FROM [Your_Part] yp
RIGHT JOIN @ListOfWeeks xxx ON yp.[Year] = xxx.[Year_Number] AND yp.[Week Number] = xxx.[Week_No]
Upvotes: 1