我一直致力于检测SQL Server中重叠时间跨度的解决方案。这是为了防止事件重叠,或者在我的情况下,工作轮班。
虽然对finding overlapping date ranges的SO进行了大量讨论,但重叠时间跨度的重要性较少,而当时间跨度允许跨越午夜时则更少。通过大量的研究和测试,我提出了以下解决方案。
CREATE TABLE Shift
(
ShiftID INT IDENTITY(1,1),
StartTime TIME(0) NOT NULL,
EndTime TIME(0) NOT NULL
);
CREATE PROCEDURE [dbo].[spInsertShift]
@StartTime TIME(0),
@EndTime TIME(0)
AS
BEGIN
DECLARE @ThrowMessage NVARCHAR(4000)
-- Check whether the new shift would overlap with any existing shifts.
IF EXISTS
(
SELECT 0
FROM Shift
WHERE
(
-- Case #1: Neither shift crosses midnight.
(@StartTime < @EndTime AND StartTime < EndTime)
-- New shift would overlap with an existing shift.
AND @StartTime < EndTime
AND StartTime < @EndTime
)
OR
(
-- Case #2: Both shifts cross midnight.
(@EndTime < @StartTime AND EndTime < StartTime)
-- New shift would overlap with an existing shift.
AND CAST(@StartTime AS DATETIME) < DATEADD(DAY, 1, CAST(EndTime AS DATETIME))
AND CAST(StartTime AS DATETIME) < DATEADD(DAY, 1, CAST(@EndTime AS DATETIME))
)
OR
(
-- Case #3: New shift crosses midnight, but the existing shift does not.
(@EndTime < @StartTime AND StartTime < EndTime)
AND
(
-- New shift would overlap with an existing shift.
@StartTime > StartTime AND @StartTime < EndTime
OR @EndTime > StartTime AND @EndTime < EndTime
OR
(
-- Existing shift would be inside new shift.
CAST(StartTime AS DATETIME) BETWEEN CAST(@StartTime AS DATETIME) AND DATEADD(DAY, 1, CAST(@EndTime AS DATETIME))
AND CAST(EndTime AS DATETIME) BETWEEN CAST(@StartTime AS DATETIME) AND DATEADD(DAY, 1, CAST(@EndTime AS DATETIME))
)
)
)
OR
(
-- Case #4: New shift does not cross midnight, but the existing shift does.
(@StartTime < @EndTime AND EndTime < StartTime)
AND
(
-- Existing shift would overlap with new shift.
StartTime > @StartTime AND StartTime < @EndTime
OR EndTime > @StartTime AND EndTime < @EndTime
OR
(
-- New shift would be inside an existing shift.
CAST(@StartTime AS DATETIME) BETWEEN CAST(StartTime AS DATETIME) AND DATEADD(DAY, 1, CAST(EndTime AS DATETIME))
AND CAST(@EndTime AS DATETIME) BETWEEN CAST(StartTime AS DATETIME) AND DATEADD(DAY, 1, CAST(EndTime AS DATETIME))
)
)
)
)
BEGIN
SET @ThrowMessage = 'A Shift already exists in this timespan.'
THROW 50140, @ThrowMessage, 1
END
INSERT INTO Shift
(
StartTime,
EndTime
)
VALUES
(
@StartTime,
@EndTime
)
END
由于我的时间跨度允许跨越午夜,我不得不使用某种机制来表示EndTime大于StartTime,尽管事实上StartTime='22:00' > EndTime='06:00'
。在这些情况下,我选择CAST
EndTime为DATETIME
并添加一天。
我的问题是:检测允许跨越午夜的重叠时间跨度的最佳方法是什么?我目前的解决方案感觉过于冗长和复杂。测试时,请记住所有timespan test cases。谢谢!
答案 0 :(得分:0)
您应该考虑在表格中添加日期字段,然后尝试处理您的数据。通过这种方式,您可以轻松找到轮班的确切时间段。
答案 1 :(得分:0)
似乎使用DATETIME而不是TIME数据类型可以完美地解决您的问题。
通过获取日期和时间信息的值,可以捕获跨越午夜的跨度,并且可以与琐碎的努力进行比较。