2010-06-02 32 views
3

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

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的 感谢任何更有效的解决方案

+0

添加索引开始/结束列。 – bobince 2010-06-02 11:53:33

+1

我认为你还应该使用A.DEMO_ID Thierry 2010-06-02 12:00:37

回答

0

这是简单,在约2秒,执行了超过20000条记录

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) 
+0

为什么不存在?我去: SELECT * FROM演示一个 其中存在( 从演示b 其中a.demo_id <> b.demo_id选择1 AND A.S Laoneo 2010-06-03 15:04:10

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索引。

+0

这里是一个资源,提供有关查询分析器中调整索引的信息:http://msdn.microsoft.com/en-us/library/aa216973%28SQL.80%29.aspx – 2010-06-02 12:08:42

+0

DEMO_ID已经是唯一的这一事实不会阻止它被连接到另一个多次返回表 – 2010-06-02 16:09:23

+0

正确 - 我编辑了查询以使事情更清楚:a.DEMO_ID,b.DEMO_ID的每个组合都可以显示两次(如果A完全在B内)。虽然在这种情况下,ID将以不同的顺序出现,所以DISTINCT不会正确删除重复。 – 2010-06-02 16:49:11

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 

您需要测量,以确保这是更快。无论如何,我们不会将所有记录的日期字段与所有其他记录进行比较,因此对于大型数据集来说,这可能会更快。

+0

您的解决方案非常有趣,但问题是u.position中的行不与位置-1重叠,但位置为-2 ....此行未返回。所以结果可能不正确。 – Laoneo 2010-06-03 09:08:28

+0

我明白了,这当然不行......对于噪音抱歉。 – marapet 2010-06-03 20:43:53

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