如何在SQL Server中确定开始班次和持续时间的最后一班

时间:2014-04-16 06:08:28

标签: sql sql-server

我有这个示例数据集

ShiftDate       Description     StartTime                   EndTime                     IsWorkShift
2014-01-01      Day Shift       2013-12-31 21:00:00.000     2014-01-01 09:00:00.000     1
2014-01-01      Night Shift     2014-01-01 09:00:00.000     2014-01-01 21:00:00.000     0
2014-01-02      Day Shift       2014-01-01 21:00:00.000     2014-01-02 09:00:00.000     1
2014-01-02      Night Shift     2014-01-02 09:00:00.000     2014-01-02 21:00:00.000     0
2014-01-03      Day Shift       2014-01-02 21:00:00.000     2014-01-03 09:00:00.000     1
2014-01-03      Night Shift     2014-01-03 09:00:00.000     2014-01-03 21:00:00.000     0
2014-01-04      Day Shift       2014-01-03 21:00:00.000     2014-01-04 09:00:00.000     1
2014-01-04      Night Shift     2014-01-04 09:00:00.000     2014-01-04 21:00:00.000     0
2014-01-05      Day Shift       2014-01-04 21:00:00.000     2014-01-05 09:00:00.000     1
2014-01-05      Night Shift     2014-01-05 09:00:00.000     2014-01-05 21:00:00.000     0

我需要在给定StartTime和持续时间

的情况下计算出EndTime

例如,如果我提供的开始时间为" 2014-01-01 21:00:00.000"和持续时间24小时

我需要" 2014-01-03 09:00:00.000"作为EndTime返回

2014-01-02  Day Shift       12 Working Hours
2014-01-02  Night Shift      0 Working Hours
2014-01-03  Day Shift       12 Working Hours

我已经使用了光标,但是当我需要使用它进行50次计算时,它变得非常慢。

ALTER FUNCTION [Maintenance].[CalendarDuration]
(
       @ServerID INT,
       @UTCStartTime DATETIME,
       @WorkingDuration INT
)
RETURNS int
AS
BEGIN
       DECLARE @UTCEndTime as Datetime;
       DECLARE @ShiftStartTime as datetime, @ShiftEndTime as datetime;
       DECLARE @ShiftDuration as int;

       DECLARE ShiftCursor CURSOR FAST_FORWARD
              FOR  SELECT t1.StartTime, t1.EndTime
              FROM config.WorkingDayShiftPatterns t1
              WHERE 
              t1.ServerID = @ServerID
              AND t1.EndTime > @UTCStartTime
              AND t1.IsWorkShift = 1
              ORDER BY t1.StartTime;

       OPEN ShiftCursor;

       FETCH NEXT FROM ShiftCursor
       INTO @ShiftStartTime, @ShiftEndTime;

       WHILE @@FETCH_STATUS = 0
       BEGIN 
              IF @ShiftStartTime < @UTCStartTime 
                     SET @ShiftStartTime = @UTCStartTime;

              SET @ShiftDuration = DATEDIFF(minute, @ShiftStartTime, @ShiftEndTime);     
              IF @ShiftDuration >= @WorkingDuration
              BEGIN
                     SET @UTCEndTime = DATEADD(minute, @WorkingDuration, @ShiftStartTime);
                     BREAK;
              END
              ELSE
                     SET @WorkingDuration = @WorkingDuration - @ShiftDuration;

              FETCH NEXT FROM ShiftCursor
              INTO @ShiftStartTime, @ShiftEndTime;
       END 

       CLOSE ShiftCursor;
       DEALLOCATE ShiftCursor;

       RETURN DATEDIFF(minute, @UTCStartTime, @UTCEndTime);
END

2 个答案:

答案 0 :(得分:2)

公用表格表达式可以找到每个班次结束时剩余的小时数,这样您就可以轻松选出最后一小时工作的班次;

DECLARE @UTCStartTime DATETIME = '2014-01-01 21:00:00.000';
DECLARE @WorkingDuration INT = 24;

WITH WorkingShifts AS (
 SELECT CASE WHEN @UTCStartTime<StartTime 
             THEN StartTime ELSE @UTCStartTime END StartTime, EndTime,
    @WorkingDuration - 
      SUM(DATEDIFF(HH, CASE WHEN @UTCStartTime<StartTime 
                            THEN StartTime ELSE @UTCStartTime 
                            END, EndTime)) 
      OVER (ORDER BY StartTime) left_after_shift
 FROM WorkingDayShiftPatterns 
 WHERE IsWorkShift=1 AND EndTime >= @UTCStartTime
)
SELECT TOP 1 DATEADD(HH, left_after_shift, EndTime) done_at
FROM WorkingShifts
WHERE left_after_shift <= 0
ORDER BY StartTime;

SQLfiddle有点累,所以这在SQL Server 2014上进行了测试。不要测试任何旧版本,但它应该至少在2012年有效。

答案 1 :(得分:0)

这会有效吗?

select min(EndTime)
from shifts
where EndTime >= DateAdd(hour, @Duration, @StartTime)