如何使用SQL在表中重叠日期不重叠

时间:2010-05-27 05:11:26

标签: tsql

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

最初我正在考虑使用如下所示的嵌套游标,但是我正在检查彼此相同的记录两次,我确信它不是很有效。

例如:此表会导致重叠。

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

4 个答案:

答案 0 :(得分:8)

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

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

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

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

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

如果你仔细观察,你会发现Start2 < End1 AND End2 > Start1定义了这种关系,所以你可以将你的表达减少到这个。


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

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

  • 最后,您可以使用INNER JOIN本身或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
    

答案 1 :(得分:3)

我不确定你想要的结果输出是什么样的,但你可以试试这个:

SELECT 
    TD1.* 
FROM 
    table1 TD1 
    JOIN table1 TD2 ON 
        TD1.start BETWEEN TD2.start AND TD2.[end] 
        AND TD1.id != TD2.id

答案 2 :(得分:1)

您可以尝试此查询。实质上,如果开始时间出现在任何其他记录的开始和结束时间之间,它会从table1中选择id。

这将获得所有“跳枪”并在另一个条目结束前开始的条目。

select id
from table1 f1
where exists(
    select 1
    from table1 f2
    where f1.id <> f2.id
        AND f1.start >= f2.start
        AND f1.start <= f2.[end]
)

答案 3 :(得分:1)

我认为您需要做的就是将结束日期与下一个开始日期进行比较,以找出重叠的内容。这可能会返回重复项,如果您只想要每个重叠的1个副本,则可能需要抛出DISTINCT。

SELECT a.* FROM Table1 a
INNER JOIN Table1 b
ON a.End > b.Start AND a.id <> b.id