【问题标题】:How do I identify the last shift given a start shift and duration in SQL Server在 SQL Server 中,如何识别给定开始班次和持续时间的最后班次
【发布时间】:2014-04-16 06:08:27
【问题描述】:

我有这个示例数据集

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 和 Duration 的情况下计算 EndTime

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

我需要“2014-01-03 09:00:00.000”作为结束时间返回

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

【问题讨论】:

  • 您是否必须处理与班次开始和结束时间不完全匹配的不规则查询?例如。这是否需要处理2014-01-02T12:00:0019 hours 的查询?

标签: sql sql-server


【解决方案1】:

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

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 年应该可以工作。

【讨论】:

  • 我使用的是 2008 R2,所以您的查询对我不起作用。但它确实让我走上了一条不同的道路,我有一个解决方法来获得看起来更复杂但现在似乎相当快的累积列。非常感谢。
【解决方案2】:

这行得通吗:

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

【讨论】:

  • 从他们的示例数据和示例查询中,这将返回2014-01-02 21:00:00.000,而不是2014-01-03 09:00:00.000,这是他们声明的所需结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多