SQL Server将时间间隔拆分为多行

SQL Server将时间间隔拆分为多行,sql,sql-server,time,split,Sql,Sql Server,Time,Split,我有以下SQL Server表 CREATE TABLE workingSchedule ( [workingDate] DATETIME NULL, [openTime] TIME (7) NULL, [closeTime] TIME (7) NULL ); INSERT INTO workingSchedule (workingDate, openTime, closeTime) VALUES ('10/1/2015','

我有以下SQL Server表

CREATE TABLE workingSchedule 
  (
      [workingDate] DATETIME NULL,
      [openTime]       TIME (7) NULL,
      [closeTime]      TIME (7) NULL
  );

INSERT INTO workingSchedule
(workingDate, openTime, closeTime)
VALUES
('10/1/2015','9:00','17:00'),
('10/2/2015','9:00','17:00');

CREATE TABLE breakTable 
  (
  [breakDate] DATETIME NULL,
  [breakStart] TIME NULL,
  [breakEnd] TIME NULL
  );

INSERT INTO breakTable
(breakDate, breakStart, breakEnd)
VALUES
('10/1/2015','12:00','13:00'),
('10/1/2015','15:00','15:30'),
('10/2/2015','12:00','13:00');
考虑到[breakTable],我试图将[workingSchedule]中的时间间隔分成几行。我想要的结果如下所示:

Date          Start    End 
10/1/2015     09:00    12:00
10/1/2015     13:00    15:00
10/1/2015     15:30    17:00
10/2/2015     09:00    12:00
10/2/2015     13:00    17:00

我不确定是否应该使用CTE、函数或临时表。如果您能分享您的解决方案代码,我将不胜感激。我可以在只有一次休息的情况下分割时间间隔,但在每天多个休息时间的情况下,我失败了。

在这种情况下,我使用ROW_NUMBER来帮助在一天内加入分割。我使用了一个UNION,但我认为您可以使用与我相同的join逻辑,但可以使用SELECT语句

SELECT  workingDate as [date], openTime as [Start], COALESCE(breakStart, closeTime) as [End]
FROM    workingSchedule
        LEFT JOIN (
            SELECT  breakDate,  breakStart, breakEnd, ROW_NUMBER() OVER (PARTITION BY breakDate ORDER BY breakStart) AS ROWNUM
            FROM    breakTable
        ) as firstBreak ON workingSchedule.workingDate = firstBreak.breakDate AND firstBreak.ROWNUM = 1
UNION
SELECT  breakStart.breakDate, breakStart.breakEnd, coalesce(breakEnd.breakStart, endTime.closeTime)
FROM    (
            SELECT  breakDate,  breakStart, breakEnd, ROW_NUMBER() OVER (PARTITION BY breakDate ORDER BY breakStart) AS ROWNUM
            FROM    breakTable
        ) as breakStart
        LEFT JOIN (
            SELECT  breakDate,  breakStart, breakEnd, ROW_NUMBER() OVER (PARTITION BY breakDate ORDER BY breakStart) AS ROWNUM
            FROM    breakTable
        ) as breakEnd ON breakStart.breakDate = breakEnd.breakDate AND breakStart.ROWNUM = breakEnd.ROWNUM - 1
        LEFT JOIN (
            SELECT  workingDate, closeTime
            FROM    workingSchedule
        ) AS endTime ON breakStart.breakDate = endTime.workingDate
这里的想法是拉开始时间,如果有第一次突破的话。如果没有中断,则合并将拉动关闭时间。然后我们在一天的休息时间结合。最后,我们将closeTime加入到最后一个break中,当没有breakEnd.breakStart时,再次使用COALESCE来使用closeTime


这里有一个SQL的提琴手在起作用:

在这样的情况下,我使用行数来帮助在一天内加入拆分。我使用了一个UNION,但我认为您可以使用与我相同的join逻辑,但可以使用SELECT语句

SELECT  workingDate as [date], openTime as [Start], COALESCE(breakStart, closeTime) as [End]
FROM    workingSchedule
        LEFT JOIN (
            SELECT  breakDate,  breakStart, breakEnd, ROW_NUMBER() OVER (PARTITION BY breakDate ORDER BY breakStart) AS ROWNUM
            FROM    breakTable
        ) as firstBreak ON workingSchedule.workingDate = firstBreak.breakDate AND firstBreak.ROWNUM = 1
UNION
SELECT  breakStart.breakDate, breakStart.breakEnd, coalesce(breakEnd.breakStart, endTime.closeTime)
FROM    (
            SELECT  breakDate,  breakStart, breakEnd, ROW_NUMBER() OVER (PARTITION BY breakDate ORDER BY breakStart) AS ROWNUM
            FROM    breakTable
        ) as breakStart
        LEFT JOIN (
            SELECT  breakDate,  breakStart, breakEnd, ROW_NUMBER() OVER (PARTITION BY breakDate ORDER BY breakStart) AS ROWNUM
            FROM    breakTable
        ) as breakEnd ON breakStart.breakDate = breakEnd.breakDate AND breakStart.ROWNUM = breakEnd.ROWNUM - 1
        LEFT JOIN (
            SELECT  workingDate, closeTime
            FROM    workingSchedule
        ) AS endTime ON breakStart.breakDate = endTime.workingDate
这里的想法是拉开始时间,如果有第一次突破的话。如果没有中断,则合并将拉动关闭时间。然后我们在一天的休息时间结合。最后,我们将closeTime加入到最后一个break中,当没有breakEnd.breakStart时,再次使用COALESCE来使用closeTime


这里有一个SQL的Fiddler在运行:

这里是获取所需输出的查询

;WITH CTEOrderedBreaks
AS
(
  SELECT row_number() over(partition by breakdate order by breakdate,breakstart asc) as rnob,
         row_number() over(partition by breakdate order by breakdate,breakstart DESC) as rnobr,
         breakdate,
         breakstart,
         breakend
  from breakTable
 ),
 CTESUMMARY
 AS
 (
   SELECT WS.WORKINGDATE,WS.OPENTIME AS [START],COB.BREAKSTART AS [END]
   FROM CTEOrderedBreaks COB INNER JOIN WORKINGSCHEDULE WS ON WS.WORKINGDATE = COB.breakdate
   WHERE COB.RNOB=1
   UNION ALL
   SELECT COB1.BREAKDATE,COB1.BREAKEND AS [START],ISNULL(COB2.BREAKSTART,WS1.CLOSETIME)AS [END]
   FROM CTEOrderedBreaks COB1 
   left JOIN CTEOrderedBreaks COB2 ON COB1.RNOB = COB2.RNOB-1 
                                           AND COB1.BREAKDATE = COB2.BREAKDATE
   LEFT JOIN workingSchedule WS1 ON WS1.WORKINGDATE = COB1.BREAKDATE AND COB1.RNOBR=1
 )

 SELECT * FROM CTESUMMARY 
 ORDER BY WORKINGDATE,START

这里是小提琴

这里是获取所需输出的查询

;WITH CTEOrderedBreaks
AS
(
  SELECT row_number() over(partition by breakdate order by breakdate,breakstart asc) as rnob,
         row_number() over(partition by breakdate order by breakdate,breakstart DESC) as rnobr,
         breakdate,
         breakstart,
         breakend
  from breakTable
 ),
 CTESUMMARY
 AS
 (
   SELECT WS.WORKINGDATE,WS.OPENTIME AS [START],COB.BREAKSTART AS [END]
   FROM CTEOrderedBreaks COB INNER JOIN WORKINGSCHEDULE WS ON WS.WORKINGDATE = COB.breakdate
   WHERE COB.RNOB=1
   UNION ALL
   SELECT COB1.BREAKDATE,COB1.BREAKEND AS [START],ISNULL(COB2.BREAKSTART,WS1.CLOSETIME)AS [END]
   FROM CTEOrderedBreaks COB1 
   left JOIN CTEOrderedBreaks COB2 ON COB1.RNOB = COB2.RNOB-1 
                                           AND COB1.BREAKDATE = COB2.BREAKDATE
   LEFT JOIN workingSchedule WS1 ON WS1.WORKINGDATE = COB1.BREAKDATE AND COB1.RNOBR=1
 )

 SELECT * FROM CTESUMMARY 
 ORDER BY WORKINGDATE,START
这是小提琴

结果是:

2015-10-01 00:00:00.000 09:00:00.0000000    12:00:00.0000000
2015-10-01 00:00:00.000 13:00:00.0000000    15:00:00.0000000
2015-10-02 00:00:00.000 09:00:00.0000000    12:00:00.0000000
结果是:

2015-10-01 00:00:00.000 09:00:00.0000000    12:00:00.0000000
2015-10-01 00:00:00.000 13:00:00.0000000    15:00:00.0000000
2015-10-02 00:00:00.000 09:00:00.0000000    12:00:00.0000000
其思想是为日期生成有序的时间,然后在第二行连接第一行,在第四行连接第三行等等


想法是为日期生成预定时间,然后在第二行加入第一行,在第四行加入第三行等等。

非常感谢!这完全符合我的问题。当我尝试在一天中增加额外的休息时间时,结果正如预期的那样。非常感谢!这完全符合我的问题。当我尝试在一天中增加额外的休息时间时,结果正如预期的那样。非常感谢!这对我的问题也很有效。这种方法也很好。我很高兴能提供帮助!:如果你有一天没有休息,这将不起作用。非常感谢!这对我的问题也很有效。这种方法也很好。我很高兴能提供帮助!:如果你有一天没有休息,这是行不通的。如果你有两次休息,一次开始,另一次结束,这是不正确的。如果你有两次休息,一次开始,另一次结束,这是不正确的。