2009-12-16 73 views
4

我有一個連接多個表的查詢並返回了很多列。Oracle:檢查其他表中是否存在行

另一個表的索引列引用這些連接表之一的PK。現在我想向查詢添加另一列,指出新表中是否存在至少一行具有該ID的行。

所以,如果我有舊錶

ID 
1 
2 
3 

和新表的一個

REF_ID 
1 
1 
1 
3 

那麼我想獲得

ID REF_EXISTS 
1   1 
2   0 
3   1 

我能想到的幾個如何做到這一點,但什麼是最優雅/高效的?


編輯 我測試提供器用50000個記錄舊錶的查詢性能,所有其他記錄兩行的新表匹配,所以一半的記錄有REF_EXISTS = 1。

如果有人感興趣,我會將平均結果作爲評論添加到答案中。感謝大家!

回答

7

另一種選擇:

select O.ID 
    , case when N.ref_id is not null then 1 else 0 end as ref_exists 
from old_table o 
left outer join (select distinct ref_id from new_table) N 
    on O.id = N.ref_id 
+0

+1因爲你用這個查詢打了我7分鐘。這個很好地將ref_id的外部參數加入到old_table之前。我會使用nvl2(n.ref_id,1,0)而不是你的大小寫表達式。 – 2009-12-16 20:34:08

+0

這是最快的查詢,平均測試時間0.06s。並且不需要GROUP BY :) – 2009-12-19 20:13:34

1

用途:

SELECT DISTINCT t1.id, 
      CASE WHEN t2.ref_id IS NULL THEN 0 ELSE 1 END AS REF_EXISTS 
    FROM TABLE_1 t1 
LEFT JOIN TABLE_2 t2 ON t2.ref_id = t1.id 

新增DISTINCT,以確保僅顯示唯一行。

+0

感謝,更新後的版本在我的測試花了大約0.17s。 – 2009-12-19 20:26:13

1

A join可能會爲一個ID返回多行,就像在示例數據中爲id=1一樣。你可以用一組通過限制每個ID一行:

SELECT 
    t1.id 
, COUNT(DISTINCT t2.ref_id) as REF_EXISTS 
FROM TABLE_1 t1 
LEFT JOIN TABLE_2 t2 ON t2.ref_id = t1.id 
GROUP BY t1.id 

group by確保有每個ID只有一行。如果找到一行,count(distinct t2.ref_id)將爲1,否則爲0。

編輯:你可以把它改寫沒有group by,但我懷疑,這將使事情easer:

SELECT 
    t1.id 
, CASE WHEN EXISTS (
     SELECT * FROM TABLE_2 t2 WHERE t2.ref_id = t1.id) 
     THEN 1 ELSE 0 END as REF_EXISTS 
, .... 
FROM TABLE_1 t1 
+0

是的,這會起作用。但我很樂意避開這個團體,因爲我正在選擇另外30個專欄......還有其他想法嗎? – 2009-12-16 19:51:07

+0

我的經驗表示使用第一個來獲得最佳效率。如果你有一個關於t2.ref_id的索引,oracle應該很聰明地使用它。請務必按照您的選擇使用EXPLAIN PLAN。 – 2009-12-16 20:17:09

+0

你是對的,第一個在我的測試中效率更高(0.20s)。它沒有使用t2.ref_id上的索引,提供使用它的提示導致了相同的性能(不同的執行計劃)。第二個查詢是唯一一個需要t2.ref_id(0.25s)索引的索引,當索引不存在時需要大約3分鐘:) – 2009-12-19 20:23:03

4

我想:

select distinct ID, 
     case when exists (select 1 from REF_TABLE where ID_TABLE.ID = REF_TABLE.REF_ID) 
    then 1 else 0 end 
    from ID_TABLE 

如果你在PK和FK上有索引,你將得到一個表掃描和索引查找。

問候 ķ

+0

謝謝,我的測試花了0.18s。 – 2009-12-19 20:24:23