按小时拆分日期/时间数据,并将日期/时间范围扩展为行

时间:2020-11-03 03:23:40

标签: sql sql-server

我正在尝试使用SQL Server将日期/时间数据范围扩展为多行。例如,我的数据看起来像

Date           StartTime    EndTime     EmployeeID     ShiftType
10/1/2019     8:30:00AM    4:57:00PM     52148          Shift
10/2/2019     9:00:00AM    5:24:00PM     72156          Shift
10/2/2019     8:27:00AM    4:40:00PM     59232          Shift

我想按小时将日期和时间范围扩展为多行。它看起来像:

Date           StartTime    EndTime     EmployeeID     ShiftType
10/1/2019     8:30:00AM    9:00:00PM     52148          Shift
10/1/2019     9:00:00AM    10:00:00PM     52148          Shift
10/1/2019     10:00:00AM   11:00:00PM     52148          Shift
10/1/2019     11:00:00AM   12:00:00PM     52148          Shift
10/1/2019     12:00:00AM   1:00:00PM     52148          Shift
10/1/2019     1:00:00AM    2:00:00PM     52148          Shift
10/1/2019     2:00:00AM    3:00:00PM     52148          Shift
10/1/2019     3:00:00AM    4:00:00PM     52148          Shift
10/1/2019     4:30:00AM    4:57:00PM     52148          Shift
10/2/2019     9:00:00AM    10:00:00PM     72156          Shift
10/2/2019     10:00:00AM   11:00:00PM     72156          Shift
                  .......

如果开始时间是8:20,则我想在前40分钟单独创建一行,因此可能是8:20 -9:00,然后是9:00-10:同一件事适用于时间结束。我很累这样的事情,但是显然它不起作用,因为我想按小时单位划分它们。

Declare @StartDate DATETIME = '2016-09-26 00:00:00.000';

With SampleDateTable AS 
  (
    SELECT @StartDate AS myDate
    UNION ALL
    SELECT DATEADD(Day,1,myDate)
    FROM Sheet1$
    WHERE DATEADD(Day,1,myDate) <=  GETDATE()
)
SELECT 
    EmployeeID,
    a.myDate,
FROM SampleDateTable a
     INNER JOIN 
      (
        SELECT EmployeeID, MIN(StartTime) MinStartTime
        FROM Sheet1$
        GROUP BY EmployeeID
      ) EachEmployee ON 
        a.MyDate >= EachEmployee.MinStartTime
     LEFT JOIN 
    Sheet1$ S ON
        EachEmployee.EmployeeID = S.EmployeeID AND
        a.myDate >= S.StartDate AND
        a.myDate <= ISNULL(S.EndDate, GETDATE())
ORDER BY EachEmployee.EmployeeID DESC, a.MyDate
OPTION (MAXRECURSION 0)

在此方面,我将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:1)

这是使用临时统计表的一种选择

示例

Declare @YourTable Table ([Date] date,[StartTime] time,[EndTime] time,[EmployeeID] int,[ShiftType] varchar(50))  
Insert Into @YourTable Values 
 ('10/1/2019','8:30:00AM','4:57:00PM',52148,'Shift')
,('10/2/2019','9:00:00AM','5:24:00PM',72156,'Shift')
,('10/2/2019','8:27:00AM','4:40:00PM',59232,'Shift')
 
Select Date
      ,StartTime = case when N=datepart(hour,StartTime) then StartTime else TimeFromParts(N,0,0,0,0) end
      ,EndTime   = case when N=datepart(hour,EndTime)   then EndTime   else TimeFromParts(N+1,0,0,0,0) end
      ,EmployeeID
      ,ShiftType
 From  @YourTable A
 Join ( values (0),(1),(2),(3),(4),(5),(6)
              ,(7),(8),(9),(10),(11),(12),(13)
              ,(14),(15),(16),(17),(18),(19),(20)
              ,(21),(22),(23)
       ) B(N)
  on  N between datepart(hour,StartTime) and datepart(hour,EndTime)

返回

Date        StartTime           EndTime             EmployeeID  ShiftType
2019-10-01  08:30:00.0000000    09:00:00.0000000    52148   Shift
2019-10-01  09:00:00.0000000    10:00:00.0000000    52148   Shift
2019-10-01  10:00:00.0000000    11:00:00.0000000    52148   Shift
2019-10-01  11:00:00.0000000    12:00:00.0000000    52148   Shift
2019-10-01  12:00:00.0000000    13:00:00.0000000    52148   Shift
2019-10-01  13:00:00.0000000    14:00:00.0000000    52148   Shift
2019-10-01  14:00:00.0000000    15:00:00.0000000    52148   Shift
2019-10-01  15:00:00.0000000    16:00:00.0000000    52148   Shift
2019-10-01  16:00:00.0000000    16:57:00.0000000    52148   Shift
2019-10-02  09:00:00.0000000    10:00:00.0000000    72156   Shift
2019-10-02  10:00:00.0000000    11:00:00.0000000    72156   Shift
2019-10-02  11:00:00.0000000    12:00:00.0000000    72156   Shift
2019-10-02  12:00:00.0000000    13:00:00.0000000    72156   Shift
2019-10-02  13:00:00.0000000    14:00:00.0000000    72156   Shift
2019-10-02  14:00:00.0000000    15:00:00.0000000    72156   Shift
2019-10-02  15:00:00.0000000    16:00:00.0000000    72156   Shift
2019-10-02  16:00:00.0000000    17:00:00.0000000    72156   Shift
2019-10-02  17:00:00.0000000    17:24:00.0000000    72156   Shift
2019-10-02  08:27:00.0000000    09:00:00.0000000    59232   Shift
2019-10-02  09:00:00.0000000    10:00:00.0000000    59232   Shift
2019-10-02  10:00:00.0000000    11:00:00.0000000    59232   Shift
2019-10-02  11:00:00.0000000    12:00:00.0000000    59232   Shift
2019-10-02  12:00:00.0000000    13:00:00.0000000    59232   Shift
2019-10-02  13:00:00.0000000    14:00:00.0000000    59232   Shift
2019-10-02  14:00:00.0000000    15:00:00.0000000    59232   Shift
2019-10-02  15:00:00.0000000    16:00:00.0000000    59232   Shift
2019-10-02  16:00:00.0000000    16:40:00.0000000    59232   Shift

答案 1 :(得分:0)

对于递归查询,您应该从示例数据开始,然后从那里进行调整。

在递归查询中,我们添加了一个额外的列:下一个小时边界,也称为NextTime。例如。对于StartTime 8:27,下一个小时边界是9:00。递归时,我们将其用作下一个StartTime,然后再次进行操作,直到达到EndTime

在结果查询中,我们隐藏NextTime列,但选择NextTimeEndTime中的较早者作为该结果行的EndTime。由于递归不能很好地提供数据,因此我们还需要按StartTime进行排序。

WITH hourly AS (
  SELECT Date, EmployeeID, ShiftType, EndTime, StartTime
       , TIMEFROMPARTS(DATEPART(hh, StartTime) + 1,
                       0, 0, 0, 0 ) AS NextTime
    FROM SampleDateTable
  UNION ALL
  SELECT Date, EmployeeID, ShiftType, EndTime, NextTime
       , TIMEFROMPARTS(DATEPART(hh, NextTime) + 1,
                       0, 0, 0, 0 ) AS NextTime
    FROM hourly
   WHERE NextTime < EndTime
)
SELECT Date, StartTime
     , CASE WHEN NextTime < EndTime THEN NextTime ELSE EndTime END AS EndTime
     , EmployeeID, ShiftType
  FROM hourly
ORDER BY Date, EmployeeID DESC, StartTime

有关工作示例,请参见SQL Fiddle

模式

CREATE TABLE SampleDateTable (
  Date        date        NOT NULL,
  StartTime   time(0)     NOT NULL,
  EndTime     time(0)     NOT NULL,
  EmployeeID  int         NOT NULL,
  ShiftType   varchar(10) NOT NULL
);

INSERT INTO SampleDateTable VALUES
( '10/1/2019', '8:30:00AM', '4:57:00PM', 52148, 'Shift' ),
( '10/2/2019', '9:00:00AM', '5:24:00PM', 72156, 'Shift' ),
( '10/2/2019', '8:27:00AM', '4:40:00PM', 59232, 'Shift' );

输出

Date        StartTime  EndTime   EmployeeID  ShiftType
2019-10-01  08:30:00   09:00:00  52148       Shift
2019-10-01  09:00:00   10:00:00  52148       Shift
2019-10-01  10:00:00   11:00:00  52148       Shift
2019-10-01  11:00:00   12:00:00  52148       Shift
2019-10-01  12:00:00   13:00:00  52148       Shift
2019-10-01  13:00:00   14:00:00  52148       Shift
2019-10-01  14:00:00   15:00:00  52148       Shift
2019-10-01  15:00:00   16:00:00  52148       Shift
2019-10-01  16:00:00   16:57:00  52148       Shift
2019-10-02  09:00:00   10:00:00  72156       Shift
2019-10-02  10:00:00   11:00:00  72156       Shift
2019-10-02  11:00:00   12:00:00  72156       Shift
2019-10-02  12:00:00   13:00:00  72156       Shift
2019-10-02  13:00:00   14:00:00  72156       Shift
2019-10-02  14:00:00   15:00:00  72156       Shift
2019-10-02  15:00:00   16:00:00  72156       Shift
2019-10-02  16:00:00   17:00:00  72156       Shift
2019-10-02  17:00:00   17:24:00  72156       Shift
2019-10-02  08:27:00   09:00:00  59232       Shift
2019-10-02  09:00:00   10:00:00  59232       Shift
2019-10-02  10:00:00   11:00:00  59232       Shift
2019-10-02  11:00:00   12:00:00  59232       Shift
2019-10-02  12:00:00   13:00:00  59232       Shift
2019-10-02  13:00:00   14:00:00  59232       Shift
2019-10-02  14:00:00   15:00:00  59232       Shift
2019-10-02  15:00:00   16:00:00  59232       Shift
2019-10-02  16:00:00   16:40:00  59232       Shift