2017-05-31 112 views
0

我有我一起工作的下列傳統的Oracle SQL查詢:混合SQL內部和外部連接

SELECT * 
FROM 
table1, table2, table3, table4 
WHERE 
    table1.job= table2.job(+) 
AND table1.event = table3.event(+) 
AND 
    ((table2.column1= table4.key AND table4.resource_type = 'xxx') 
    OR (table2.column2 = table4.key AND table4.resource_type = 'yyy')) 

我看到,表中有一個左外連接對錶2和表1有一個左外連接上表3。但是現在最後的條款是做什麼的?

當我看着維恩圖時,我認爲它會返回table1和table4和table4共有的記錄。那麼這個查詢是否會執行兩個數據集的聯合?

+1

如果您在where子句中使用現代顯式的'JOIN'語法代替古老的過時隱式連接,事情會更容易理解(此外,即使Oracle建議不要使用專有的(+) 'any more) –

+0

請編輯您的問題幷包含爲上述查詢生成的查詢計劃。謝謝。 –

回答

1

LEFT JOINtable2確實是INNER JOINWHERE子句將撤消外部聯接。所以,我認爲這是相當於查詢:

SELECT * 
FROM table1 JOIN 
    table2 
    ON table1.job = table2.job JOIN 
    table4 
    ON (table2.column1 = table4.key AND table4.resource_type = 'xxx') OR 
     (table2.column2 = table4.key AND table4.resource_type = 'yyy') LEFT JOIN 
    table3 
    ON table1.event = table3.event; 

Just to be clear關於轉動外點連接到內部連接:

如果WHERE子句包含一列從 表比較的條件B使用常量,那麼必須將(+)運算符應用於 列,以便Oracle返回表A的行,對於該列,該行具有 生成的空值。否則,Oracle只返回簡單連接的 結果。

+0

但table2沒有與常量進行比較,而是將其與另一個表中的列進行比較。 – codecypher

+0

@codecypher。 。 。所以?沒有'(+)',所以它要求列有一個非NULL值。因此,這解除了外連接。 –

0

表4記錄了(至少)兩種資源類型{'xxx','yyy'}。表2具有列1中的資源類型'xxx'和列2中的資源類型'yyy'的對應ID。

0

最後一個條款,即((table2.column1= table4.key AND table4.resource_type = 'xxx') OR (table2.column2 = table4.key AND table4.resource_type = 'yyy'))實際上將table2上的「左連接」變爲連接,更多特別是到之類的東西,使查詢將而不是必然包含table1的所有記錄。

你能想到的,如下:假設table1table2實際上是左加入,使得(中間)結果包含table1所有元組的table2屬性組合,其中table1.jobtable2.job匹配,並且對於空值table2 - 屬性job不匹配。然後,如table2.column1= table4.key那樣的where-條件將從(中間)結果中移除所有記錄,其中table2.column1不匹配table4中的任何記錄;請注意,null - 由左連接產生的table2.column1中的值將永遠不匹配,並且會讓這些記錄被過濾掉。因此,table1.jobtable2.job不匹配的結果中不會有任何記錄。