关于sql:展开\\”From\\”

Expand "From" & "To" date columns to 1 row per day within that range

取以下样本数据:

1
2
3
4
5
6
7
8
9
10
WITH SampleData AS (
    SELECT '8000213' AS EmployeeID, '2014-08-25 00:00:00.000' AS StartDate, '2014-08-31 00:00:00.000' AS EndDate, 28.5 AS HPW
    UNION ALL
    SELECT '8000213' AS EmployeeID, '2014-10-01 00:00:00.000' AS StartDate, NULL AS EndDate, 33 AS HPW
    UNION ALL
    SELECT '0003289' AS EmployeeID, '2014-04-25 00:00:00.0000' AS StartDate, '2014-04-30 00:00:00.000' AS EndDate, 36 AS HPW
    UNION ALL
    SELECT '0003289' AS EmployeeID, '2014-05-01 00:00:00.000' AS StartDate, NULL AS EndDate, 20 AS HPW
)
SELECT * FROM SampleData

我们如何扩展这个数据如下(当没有结束日期时,假设当前日期):

enter image description here

我怀疑这里需要某种递归/CTE/计数表,但我无法理解它!


制作日期生成器的方法有很多种;整篇文章都专门讨论了哪一篇最快,但为了简单起见,我将调整此处找到的那一篇。我建议对该主题进行一些阅读,并在数据库中保留一个真实的日期表,您可以将其用于此类查询(而不是为您执行的每个查询即时生成一个)。

第一步:创建日期表

第二步:将表中的每个日期连接到员工(注意:我也在过滤这个以仅显示大于 SampleData 中最小开始日期的日期)

第三步:将日期/不同员工加入您的数据,以检索到给定日期有效的 HPW。

SQL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
DECLARE @StartDate DATETIME = '2014-01-01 00:00:00.000'; -- this can be any date below the minimum StartDate

WITH SampleData AS (
    SELECT '8000213' AS EmployeeID, '2014-08-25 00:00:00.000' AS StartDate, '2014-08-31 00:00:00.000' AS EndDate, 28.5 AS HPW
    UNION ALL
    SELECT '8000213' AS EmployeeID, '2014-10-01 00:00:00.000' AS StartDate, NULL AS EndDate, 33 AS HPW
    UNION ALL
    SELECT '0003289' AS EmployeeID, '2014-04-25 00:00:00.000' AS StartDate, '2014-04-30 00:00:00.000' AS EndDate, 36 AS HPW
    UNION ALL
    SELECT '0003289' AS EmployeeID, '2014-05-01 00:00:00.000' AS StartDate, NULL AS EndDate, 20 AS HPW
),
SampleDateTable AS
  (
    SELECT @StartDate AS myDate
    UNION ALL
    SELECT DATEADD(DAY,1,myDate)
    FROM SampleDateTable
    WHERE DATEADD(DAY,1,myDate) <=  GETDATE()
)
SELECT
    EachEmployee.EmployeeID,
    a.myDate,
    SampleData.HPW
FROM
    SampleDateTable a
     INNER JOIN
      (
        SELECT EmployeeID, MIN(StartDate) MinStartDate
        FROM SampleData
        GROUP BY EmployeeID
      ) EachEmployee ON
        a.MyDate >= EachEmployee.MinStartDate
     LEFT JOIN
    SampleData ON
        EachEmployee.EmployeeID = SampleData.EmployeeID AND
        a.myDate >= SampleData.StartDate AND
        a.myDate <= ISNULL(SampleData.EndDate, GETDATE())
ORDER BY EachEmployee.EmployeeID DESC, a.MyDate
OPTION (MAXRECURSION 0)

或者,您可以简单地继续 CTE:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
--Replace the enddate with"Getdate()" if you require expansion until"today/current"
DECLARE @DefaultEnddate Datetime = '2014-10-15 00:00:00.000'

;WITH SampleData AS (
SELECT '8000213' AS EmployeeID, '2014-08-25 00:00:00.000' AS StartDate, '2014-08-31 00:00:00.000' AS EndDate, 28.5 AS HPW
UNION ALL
SELECT '8000213' AS EmployeeID, '2014-10-01 00:00:00.000' AS StartDate, NULL AS EndDate, 33 AS HPW
UNION ALL
SELECT '0003289' AS EmployeeID, '2014-04-25 00:00:00.000' AS StartDate, '2014-04-30 00:00:00.000' AS EndDate, 36 AS HPW
UNION ALL
SELECT '0003289' AS EmployeeID, '2014-05-01 00:00:00.000' AS StartDate, NULL AS EndDate, 20 AS HPW
)
, Base AS ( SELECT EmployeeID, StartDate = CONVERT(datetime, StartDate) , EndDate = CONVERT(datetime,isnull(EndDate,@DefaultEnddate)), HPW FROM SampleData)
, Expanded AS (SELECT EmployeeID, StartDate AS [DATE], HPW , EndDate FROM Base
                UNION ALL
                SELECT EmployeeID, [DATE] = [DATE] + 1, HPW , EndDate FROM Expanded WHERE [DATE] < EndDate
        )
SELECT EmployeeID,[DATE], HPW
FROM Expanded
ORDER BY EmployeeID, [DATE]
OPTION (MAXRECURSION 1000)