在SQL表中查找有效的重叠条目

时间:2010-06-02 11:48:39

标签: sql sql-server sql-server-2008

查找与同一表中的其他条目重叠的所有条目的最有效方法是什么?每个条目都有一个开始和结束日期。例如,我有以下数据库设置:

CREATE TABLE DEMO
(
    DEMO_ID  int  IDENTITY ,
    START date  NOT NULL ,
    END  date  NOT NULL
);

INSERT INTO DEMO (DEMO_ID, START, END) VALUES (1, '20100201', '20100205');
INSERT INTO DEMO (DEMO_ID, START, END) VALUES (2, '20100202', '20100204');
INSERT INTO DEMO (DEMO_ID, START, END) VALUES (3, '20100204', '20100208');
INSERT INTO DEMO (DEMO_ID, START, END) VALUES (4, '20100206', '20100211');

我的查询如下:

SELECT DISTINCT * 
FROM DEMO A, DEMO B
WHERE A.DEMO_ID != B.DEMO_ID
AND A.START < B.END
AND B.START < A.END

问题是当我的演示表有例如20'000行时,查询花费的时间太长。我的环境是MS SQL Server 2008。 感谢您提供更有效的解决方案

4 个答案:

答案 0 :(得分:0)

您可以稍微重写一下查询:

SELECT A.DEMO_ID, B.DEMO_ID 
FROM DEMO A, DEMO B
WHERE A.DEMO_ID != B.DEMO_ID
AND A.START >= B.START
AND A.START <= B.END

删除DISTINCT关键字可能会使事情变得更便宜,因为Sql Server会对返回的列(当您使用DISTINCT *时都是这样做)进行排序以消除重复项。

您还应该考虑添加索引。在Sql Server 2008中,我建议使用包含DEMO_ID的START,END索引。

答案 1 :(得分:0)

使用函数或存储过程:

首先,订购按开始和结束

的条目
DECLARE @t table (
    Position int identity(1,1),
    DEMO_ID  int,
    START date  NOT NULL ,
    END  date  NOT NULL
)
INSERT INTO @t (DEMO_ID, START, END)
    SELECT DEMO_ID, START, END
    FROM DEMO
    ORDER BY START, END

然后检查上一个下一个记录的重叠:

SELECT t.DEMO_ID
FROM @t t INNER JOIN @t u ON t.Position + 1 = u.Position
WHERE u.Start <= t.End
UNION
SELECT t.DEMO_ID
FROM @t t INNER JOIN @t u ON t.Position - 1 = u.Position
WHERE t.Start <= u.End

您需要衡量以确保更快。在任何情况下,我们都不会将所有记录的日期字段与所有其他记录进行比较,因此对于大型数据集来说这可能会更快。

答案 2 :(得分:0)

这更简单,并且在超过20000条记录的约2秒内执行

select * from demo a
where not exists(
select 1 from demo b 
where a.demo_id!=b.demo_id
AND A.S < B.E
AND B.S < A.E)

答案 3 :(得分:0)

迟到的答案,但想知道这是否会有所帮助:

create index IXNCL_Demo_DemoId on Demo(Demo_Id)

select a.demo_id, b.demo_id as [CrossingDate]
from demo a
    cross join demo b
    where a.[end] between b.start and b.[end]
    and a.demo_id <> b.demo_id