首页 > 解决方案 > 使用 SQL Server 每周创建日历表

问题描述

我正在使用 Microsoft SQL Server 2012,我想创建下表(从 2018-12-02 到 2019-08-31):

Clinic_code Clinic_name        Day_start        Day_end         Weeks_passed
-----------------------------------------------------------------------------
   A123       NAME1           2018-12-02      2018-12-08             1      
   A124       NAME2           2018-12-02      2018-12-08             1      
   A125       NAME3           2018-12-02      2018-12-08             1      
   [...]
   A123       NAME1           2018-12-09      2018-12-15             2 
   A124       NAME2           2018-12-09      2018-12-15             2 
   A125       NAME3           2018-12-09      2018-12-15             2 
   [...]
   A123       NAME1           2018-12-16      2018-12-22             3
   A124       NAME2           2018-12-16      2018-12-22             3
   A125       NAME3           2018-12-16      2018-12-22             3

我正在使用以下代码:

DECLARE @fromstartdate date = '2018-12-02'
DECLARE @fromenddate date = '2018-12-08'

SELECT 
    #MyTable.*, B.Day_start, C.Day_end, 
    DATEDIFF(day, MIN(B.Day_start) OVER (), 
    B.Day_start) + 1 AS Weeks_passed
FROM  
    #MyTable
CROSS APPLY 
    (SELECT TOP (DATEDIFF(DAY, @fromstartdate, DATEADD(Month, 9, @fromstartdate))) 
         Day_start = CONVERT(date, DATEADD(DAY, -1 + 7 * ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), @fromstartdate))
     FROM master..spt_values n1) B
CROSS APPLY
    (SELECT TOP (DATEDIFF(DAY, @fromenddate, DATEADD(Month, 9, @fromenddate))) 
         Day_end = CONVERT(date, DATEADD(DAY, -1 + 7 * ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), @fromenddate))
     FROM master..spt_values n1) C

但我没有得到第一个@fromstartdate@fromenddate而且它已经超过了 2019 年 8 月 31 日。你能告诉我我做错了什么吗?

标签: sqlsql-servertime-series

解决方案


我会选择创建递归公用表表达式并将其加入您的表的方法。使用 CTE,您可以创建日期列表并通过在每周的每个开始添加 6 天来定义日期范围。通过的周数按增量计算。

DECLARE @fromstartdate date = '2018-12-02'
DECLARE @fromenddate date = '2019-08-31'

;WITH cteDateList AS
(
    SELECT @fromstartdate AS Day_start, DATEADD(D, 6, @fromstartdate) AS Day_end, 1 AS Weeks_passed
    UNION ALL
    SELECT DATEADD(D, 7, Day_start), DATEADD(D, 6, Day_end), Weeks_passed + 1 FROM cteDateList
    WHERE DATEADD(D, 7, Day_start) <= @fromenddate
)


SELECT mt.clinic_code, mt.clinic_name, dl.* FROM MyTable mt
CROSS APPLY (SELECT * FROM cteDateList) dl
ORDER BY dl.Day_start, mt.clinic_code;

推荐阅读