如何使用TSQL检查日期在表中不重叠

Jon*_*Jon 4 t-sql

我有一个包含开始和结束日期时间的表,我需要确定是否有任何重叠并且不确定最佳方式.

最初我正在考虑使用如下所示的嵌套游标,这确实有效,但是我正在检查彼此相同的记录两次并且我确定它不是非常有效.

例如:这个表会导致重叠.

id  start                       end
-------------------------------------------------------
1   2009-10-22 10:19:00.000     2009-10-22 11:40:00.000
2   2009-10-22 10:31:00.000     2009-10-22 13:34:00.000
3   2009-10-22 16:31:00.000     2009-10-22 17:34:00.000

Declare @Start datetime, @End datetime, @OtherStart datetime, @OtherEnd datetime, @id int, @endCheck bit

Set @endCheck = 0

DECLARE Cur1 CURSOR FOR
        select id, start, end from table1 

OPEN Cur1
FETCH NEXT FROM Cur1 INTO @id, @Start, @End
WHILE @@FETCH_STATUS = 0 AND @endCheck = 0
BEGIN
    -- Get a cursor on all the other records
    DECLARE Cur2 CURSOR FOR
            select start, end from table1 
                and id != @id AND start < @end
    OPEN Cur2
    FETCH NEXT FROM Cur2 INTO @OtherStart, @OtherEnd
    WHILE @@FETCH_STATUS = 0 AND @endCheck = 0
    BEGIN

            if ( @Start > @OtherStart AND @Start < @OtherEnd    OR
                 @End > @OtherStart AND @End < @OtherEnd )
                or
               ( @OtherStart > @Start AND @OtherStart < @End    OR
                 @OtherEnd > @Start AND @OtherEnd < @End )

            BEGIN
                SET @endCheck = 1
            END

            FETCH NEXT FROM Cur2 INTO @OtherStart, @OtherEnd
    END
    CLOSE Cur2
    DEALLOCATE Cur2

    FETCH NEXT FROM Cur1 INTO @id, @Start, @End
END
CLOSE Cur1
DEALLOCATE Cur1
Run Code Online (Sandbox Code Playgroud)

lc.*_*lc. 8

  • 首先,让我们详尽地检查"重叠"的含义并优化您的布尔表达式.

重叠是以下任何一种情况:

                 Start1                     End1
---------------------------------------------------------------------------------
 Start2                       End2
 Start2                                                       End2
                             Start2                           End2

并且不是以下任何一种情况:

                 Start1                     End1
---------------------------------------------------------------------------------
 Start2  End2
                                                      Start2  End2

如果你仔细观察,你会注意到Start2 < End1 AND End2 > Start1这种关系的定义,所以你可以减少你的表达.


  • 其次,您可以将其置于WHERE光标的条件中,而不是循环遍历每一行并进行检查.

  • 第三,既然你只是检查某些东西是否存在,你可以使用一个IF EXISTS子句而不是循环游标并检查.

  • 最后,您可以使用INNER JOINon本身或者WHERE EXISTS根据您希望最终输出的显示方式将所有内容压缩为单个查询.要获得表中的所有重叠,您可以尝试类似下面的内容(t2.id > t1.id只是每次重叠一次):

    SELECT t1.id, t2.id
    FROM MyTable t1
    INNER JOIN MyTable t2 ON t2.id > t1.id 
                          AND t2.start < t1.end AND t2.end > t1.start
    
    Run Code Online (Sandbox Code Playgroud)