2017-02-10 111 views
1

我最近問這個問題,有點爲難,所以我想請問專家...SQL語句返回非交叉記錄

鑑於兩個表& B,我要回所有的值從A和B不重疊。想想兩個重疊的圓圈;我們如何返回不在重疊中心部分的所有數據?而且,我必須使用ANSI標準SQL而不是Oracle語法。

假設我們希望一切獨家既是& B,我的回答是

select * 
    from A 
    cross join B 
    minus 
    (select a.common_column from a 
    intersect 
    select b.common_column) 

這是否看起來是正確的,甚至接近?如果這是正確的,是否有更有效的方法來做到這一點?

順便說一句 - 我的解決方案被完全拒絕....

謝謝!

+0

看起來很接近。我會用'union all'來代替外部查詢的交叉連接。 –

+0

你爲什麼要進行交叉連接?這將創建A和B的笛卡爾積。假設A和B包含多個列,此查詢將不會編譯(因爲交叉連接B返回NxM列,而第二部分返回1列)。 –

+0

是的,你不需要'交叉連接'....要麼在'intersect'上做'union all',然後'except',要麼在'select col'上做一個'union all'除了從B'中選擇col和'從B中選擇列外,除了從A中選擇col' – 2017-02-10 18:45:11

回答

1

可能是全外連接?

select coalesce(A.col, B.col) 
from A full outer join B on A.col = B.col 
where A.col is null or B.col is null; 
0

對於計算一組對稱的區別,你可以使用的MINUSUNION ALL組合:

select * from (
    (select * from A 
    minus 
    select * from B) 
    union all 
    (select * from B 
    minus 
    select * from A) 
) 
+0

從邏輯上說,這是正確的。但是完整的外部聯接解決方案更加高效 - 即在桌面上傳遞的次數更少。 – BobC

+0

@BobC通常,我只將它作爲即席查詢運行,所以我不擔心太多的性能問題。我發現這個解決方案的可讀性和寫入速度比完整的外部聯接更加可讀,但是YMMV。 –

+0

我非常關心性能(這是我的工作):)所以我只是想指出這些東西:) – BobC

0

您將需要從兩個表中選擇所有的數據,除了它們的重疊部分,然後將數據與工會結合起來。提供的代碼應該適用於您的示例。

SELECT * 
FROM 
    (
    SELECT * FROM Table1 
    EXCEPT SELECT * FROM Table2 
) 
UNION 
SELECT * 
FROM 
    (
    SELECT * FROM Table2 
    EXCEPT SELECT * FROM Table1 
) 

希望這會有所幫助。

+1

由於子查詢會產生不相交的元組集合,因此union all將返回相同的結果集並可能導致更好的性能。 – 2017-02-10 18:48:04

+0

您可能想要在第二個查詢中使用'select *' - 否則,這將返回一個解析錯誤,除非table1和table2僅包含單個列'item'。 –

+0

我甚至都不知道Oracle有一個EXCEPT函數。有些東西讓我學習。謝謝! 哎呀 - 看起來像MINUS在Oracle中工作,而EXCEPT在其他系統中工作。 – CarCrazyBen

0

您的查詢被拒絕,因爲它在語法上不正確:列數不同,它會混淆cross joinunion all。不過,我認爲你有解決這個問題的正確思路。

您可以輕鬆地解決這個問題:

(select * 
from A 
union all 
select * 
from B 
) minus 
(select * 
from A 
intersect 
select * 
from B 
); 

也就是說,使用union all結合一切,然後減去發生的兩個表中的行。

當然,如果有單一的id,那麼你可以使用id爲join等操作。

+0

這是我正在瞄準的解決方案....我通過使用交叉連接而不是聯盟全部來解決它。 謝謝! – CarCrazyBen

0

就像弗蘭克·施密特在此期間回答:

這是包括數據例如:

WITH 
table_a(name) AS (
      SELECT 'From_A_1' 
UNION ALL SELECT 'From_A_2' 
UNION ALL SELECT 'From_A_3' 
UNION ALL SELECT 'From_A_4' 
UNION ALL SELECT 'From_A_5' 
UNION ALL SELECT 'From_BOTH_6' 
UNION ALL SELECT 'From_BOTH_7' 
UNION ALL SELECT 'From_BOTH_8' 
) 
, 
table_b(name) AS (
      SELECT 'From_B_1' 
UNION ALL SELECT 'From_B_2' 
UNION ALL SELECT 'From_B_3' 
UNION ALL SELECT 'From_B_4' 
UNION ALL SELECT 'From_B_5' 
UNION ALL SELECT 'From_BOTH_6' 
UNION ALL SELECT 'From_BOTH_7' 
UNION ALL SELECT 'From_BOTH_8' 
) 
(SELECT * FROM table_a EXCEPT SELECT * FROM table_b) 
UNION ALL 
(SELECT * FROM table_b EXCEPT SELECT * FROM table_a) 
ORDER BY name 
; 

name 
From_A_1 
From_A_2 
From_A_3 
From_A_4 
From_A_5 
From_B_1 
From_B_2 
From_B_3 
From_B_4 
From_B_5 
1

鑑於表A和B,你正在尋找(AUB) - (A & B)。換句話說,你需要一個工會B減去他們的交集。記住A和B必須是聯合兼容才能使此查詢生效。我會這樣做:

(select * from A 
union 
select * from B 
) 
minus 
(select * from A 
    intersect 
select * from B 
)