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

时间:2015-08-29 03:15:41

标签: sql sql-server time split

我有以下SQL Server表。

mypage.*

考虑到[breakTable],我试图将[workingSchedule]中的时间间隔分成几行。我想要的结果是这样的:

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');

我不确定是否应该使用CTE,函数或临时表。如果您能分享您的解决方案代码,我感谢您。当只有一次休息时,我能够分割时间间隔,但是当我达到每天多次休息时间时,我失败了。

5 个答案:

答案 0 :(得分:0)

在这种情况下,我使用ROW_NUMBER(https://msdn.microsoft.com/en-us/library/ms186734.aspx)来帮助在一天内加入分组。我使用了UNION,但我认为你可以使用相同的连接逻辑,但是可以使用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

这里的想法是拉出开始时间,如果有的话,第一次休息。如果没有中断,COALESCE将取代closeTime。然后我们整天休息。最后,我们将closeTime加入到最后一个中断,再次使用COALESCE在没有" breakEnd.breakStart"时使用closeTime。

以下是其中的SQL Fiddler:http://sqlfiddle.com/#!6/5a4765/14

答案 1 :(得分:0)

以下是获得所需输出的查询

;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

这是小提琴http://sqlfiddle.com/#!3/4076a/21

答案 2 :(得分:0)

You can try this


DECLARE @Tab TABLE
(
[Date] [datetime],
[Time] [time],
[Row] int
)

DECLARE @Tab2 TABLE
(
[Date] [datetime],
[Row] int
)

INSERT INTO @Tab2
SELECT DISTINCT(workingDate) , ROW_NUMBER() OVER(ORDER BY [workingDate])
FROM workingSchedule 

DECLARE @Count int;
DECLARE @Num [int];
DECLARE @Dat [datetime];
SET @Num=1;
SET @Count=(SELECT count(*) FROM @Tab2 t)

WHILE @Num<=@Count
BEGIN
SET @Dat=(SELECT [Date] FROM @Tab2 t WHERE t.[Row]=@Num)

INSERT INTO @Tab
SELECT * , ROW_NUMBER() OVER( ORDER BY Cte4.breakStart) Number  FROM  (
SELECT *  FROM(
SELECT Cte.breakDate, Cte.breakStart  FROM 
(SELECT * FROM breakTable 
UNION ALL
SELECT * FROM workingSchedule
)Cte 
WHERE Cte.breakDate=@Dat  
)Cte2

UNION ALL

SELECT * FROM(
SELECT Cte.breakDate, Cte.breakEnd  FROM 
(SELECT * FROM breakTable 
UNION ALL
SELECT * FROM workingSchedule
)Cte 
WHERE Cte.breakDate=@Dat
)Cte3
)Cte4
ORDER BY Cte4.breakStart
SET @Num=@Num+1;
END
;WITH Cte AS
(
SELECT * FROM @Tab t
WHERE t.[Row]%2=0
),
 Cte2 AS
(
SELECT * FROM @Tab t
WHERE t.[Row]%2=1
)
SELECT  DISTINCT Cte.[Date],Cte2.[Time] AS Start, Cte.[Time] AS [End] FROM Cte
INNER JOIN
Cte2 
ON
(Cte2.[Row]+1)=Cte.[Row]

答案 3 :(得分:0)

create table #answer
(workdate datetime null,
    starttime time null,
    endtime time null
)
declare cur cursor for (select workingDate,openTime,closeTime from workingSchedule)
declare @workingDate datetime,@openTime time,@closeTime time,@breakStart time,@breakEnd time,@breakEnd2 time,@counter int
set @counter = 0;
open cur
fetch cur into @workingDate,@openTime,@closeTime
while(@@FETCH_STATUS =0)
begin
declare cur2 cursor for select breakStart,breakEnd from breakTable  where breakDate = @workingDate order by breakStart
open cur2
fetch cur2 into @breakStart,@breakEnd
set @counter = 1;
while(@@FETCH_STATUS=0)
begin
if(@counter = 1)
begin
    insert into #answer values(@workingDate,@openTime,@breakStart)
end
else
begin
insert into #answer values(@workingDate,@breakEnd2,@breakStart)
end
set @breakEnd2 = @breakEnd
set @counter = @counter+1;


fetch cur2 into @breakStart,@breakEnd

end
close cur2
deallocate cur2
fetch cur into @workingDate,@openTime,@closeTime
end
close cur
deallocate cur
select * from #answer
drop table #answer

冲锋是:

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

答案 4 :(得分:0)

;with cte as(
             select *, row_number() over(partition by wd order by ot) rn
             from
                (select workingDate wd, openTime ot from workingSchedule
                 union
                 select workingDate, closeTime from workingSchedule
                 union
                 select breakDate, breakStart from breakTable
                 union
                 select breakDate, breakEnd from breakTable)t)
select c1.wd, c1.ot, c2.ot
from cte c1
join cte c2 on c1.wd = c2.wd and c1.rn + 1 = c2.rn and c1.rn % 2 = 1
order by c1.wd, c1.ot

想法是生成日期的有序时间,然后加入第二行的第一行,第四行的第三行......