SQL:按连续日期计算的记录数,即使日期不存在记录

时间:2017-08-17 11:00:24

标签: sql sql-server sql-server-2008 tsql

我正在使用SQL Server 2008 R2。

我正在查询医院预约老虎机的表格,并尝试返回一个列表,列出特定医生被标记为已预订的预约时段,按周数/年分组。

有些星期的例子还没有任何预约约会,但我希望结果列出所有即将到来的几周,即使预订的预约时段的数量为零。

我正在寻找的输出是这样的:

-------------------------------------------
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

我知道聚合结果的标准选择不会显示记录数为零的那几周,因为没有什么可以返回 - 所以我试图通过使用cte首先生成一个列表来解决这个问题所有即将到来的几周。

但是,尽我所能,我无法让查询显示零周......

我已经看到了许多与此类似问题的解决方案,但是尽管进行了实验,我还是无法将它们应用于我的特定问题(包括SQL Count to include zero values

这是我到目前为止所写的查询的最新版本。

    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

它返回给我的结果是正确的,但我只是需要它将那些周列入计数为零的列表中。

任何人都可以解释我哪里出错了吗?我猜我没有正确加入cte,但我尝试了左右连接,产生相同的结果。我也尝试通过swopping上面的查询语句和cte around来反转查询,但这也不起作用。

感谢任何人可以建议的任何指导。

2 个答案:

答案 0 :(得分:1)

只有RIGHT JOIN @ListOfWeeks表到您拥有的结果集:

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]

答案 1 :(得分:0)

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