如何不使用UNION按日期范围分组?附SQL Server 2012 T-SQL代码
解决方案:用递归CTE生成周范围,替代循环查询
嘿,我明白你现在的需求——原来的循环会每次输出一周的结果,现在想把这些周的数据整合在一起,不用UNION拼接多次查询,同时按日期范围(每周)来分组处理对吧?
针对SQL Server 2012,推荐用**递归CTE(公共表表达式)**来生成你需要的8个周的日期范围,然后一次性关联所有数据,这样既避免了循环的低效,也不用写一堆UNION。
完整实现代码
DECLARE @START DATE, @END DATE; -- 假设这里已经给@START和@END赋值,比如SET @START = '2024-01-01', @END = '2024-01-07'; WITH WeeklyRanges AS ( -- 初始行:第0周(也就是你最初的@START和@END对应的周) SELECT 0 AS WeekOffset, -- 标记是往前推了几周,0是当前周,7是最老的那周 @START AS WeekStart, @END AS WeekEnd UNION ALL -- 递归生成往前的7周,直到总共8周(0到7) SELECT WeekOffset + 1, DATEADD(wk, -1, WeekStart), DATEADD(wk, -1, WeekEnd) FROM WeeklyRanges WHERE WeekOffset < 7 ) -- 关联周范围、预约单和就诊记录 SELECT wr.WeekOffset, wr.WeekStart, wr.WeekEnd, Visits.idPatient, Visits.VDay, so.SDay FROM WeeklyRanges wr -- 先关联所有预约单,再左连接对应周的就诊记录 CROSS JOIN tblScheduledOrder so LEFT OUTER JOIN ( SELECT idPatient, DATEPART(dw, VDate) - 1 AS VDay, VDate FROM tblVisits ) Visits ON so.idPatient = Visits.idPatient AND Visits.VDate BETWEEN wr.WeekStart AND wr.WeekEnd -- 如果需要按周分组统计,比如每个周的就诊数,可以加GROUP BY -- GROUP BY wr.WeekOffset, wr.WeekStart, wr.WeekEnd, Visits.idPatient, Visits.VDay, so.SDay OPTION (MAXRECURSION 10); -- SQL Server默认递归次数是100,这里只需要8次,所以设置10足够
代码说明
- 递归CTE生成周范围:
- 初始部分定义了第0周的起始和结束日期;
- 递归部分每次把日期往前推1周,直到生成8个周(
WeekOffset从0到7)。
- 关联数据:
- 用
CROSS JOIN先取出所有预约单记录; - 左连接就诊记录时,通过
Visits.VDate BETWEEN wr.WeekStart AND wr.WeekEnd确保只匹配对应周的就诊数据,同时保留没有就诊记录的预约单(符合你原来LEFT OUTER JOIN的逻辑)。
- 用
- 分组处理:
- 如果需要按周做聚合统计(比如每个周每个患者的就诊次数),直接在
SELECT里加聚合函数(比如COUNT(Visits.idPatient)),然后按wr.WeekOffset、wr.WeekStart等字段分组即可。
- 如果需要按周做聚合统计(比如每个周每个患者的就诊次数),直接在
这个方法比原来的循环高效得多,因为是单次查询,减少了多次执行SELECT的开销,而且结果集是统一的,方便后续处理。
内容的提问来源于stack exchange,提问作者paulvd
相关产品推荐
相关产品推荐

