2010-06-02 30 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