2008-10-09 79 views
16

爲什麼組合內部連接時外部表的重要性如何? 以下失敗,Postgres的:內連接和外連接;表中的重要順序是?

SELECT grp.number AS number,  
     tags.value AS tag 
FROM groups grp, 
    insrel archiverel 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 AND  
     archiverel.dnumber = grp.number 

與結果:

ERROR: invalid reference to FROM-clause entry for table "grp" LINE 5: LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.d... 
^ HINT: There is an entry for table "grp", but it cannot be referenced from this part of the query. 

在組在這一切的作品逆轉:

SELECT grp.number AS number,  
     tags.value AS tag 
FROM insrel archiverel, 
     groups grp 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 AND  
     archiverel.dnumber = grp.number 
+0

這是非常有趣的。這與混合連接約定有關。我有點驚訝,第二個版本甚至有效! – 2008-10-09 13:07:11

回答

20

我相信你可以把它想象成運營商優先權問題。

當你這樣寫:

FROM groups grp, 
    insrel archiverel 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 

,我認爲它是由解析器這樣解釋:

FROM groups grp, 
(
    (
    insrel archiverel 
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
) 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
) 

如果是這樣,那麼在最裏面加入「GRP」是綁定。

當您使用「groups」和「insrel」反轉線條時,最內部的連接適用於「groups」和「ownrel」,因此它可以工作。

也許這會工作,以及:

FROM groups grp 
     JOIN insrel archiverel ON archiverel.dnumber = grp.number 
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
    LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 
5

因爲在第一個GRP是不屬於ON子句所屬的連接的一部分。

+0

這是唯一對我有意義的評論,它修復了我的查詢。我在FROM子句中移動了一個表作爲FROM子句中的最後一個,並修復了錯誤。 – 2015-03-31 20:34:37

4

我不知道是什麼導致了這種行爲,如果它是一個錯誤或設計,但它應該工作正常,如果你堅持一種形式的連接或其他。

SELECT grp.number AS number,  
     tags.value AS tag 
FROM groups grp 
JOIN insrel archiverel ON archiverel.dnumber = grp.number 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 

我很想知道更多,如果行爲是由設計。

2

對於內部聯接,表的順序並不重要。

對於外連接,它是。 全部將包含指定側(表示爲LEFT或RIGHT連接)的表中的行,而只有符合連接條件的行纔會包含在另一側的表中。

因爲OUTER JOINS從一側保留所有行,所以它們被稱爲(通常)增加結果集。 INNER JOINS只保留來自雙方的行,如果它們匹配的話,所以它們(通常)被稱爲減少結果集。因此,您通常希望在OUTER JOINS(在可能的情況下)之前執行您的INNER JOINS。

就你而言,這幾乎肯定是邪惡的A,B語法的結果。

+0

true,但它不是導致問題的連接順序,而是來自子句 – 2008-10-09 13:33:08

+0

@Thies:WTFalse中的順序。連接的順序在from子句中指定,所以「連接的順序」實際上是「from子句中連接的順序」,並且*是問題,因爲順序很重要。如果在內部連接之前執行外部連接,則內部連接會減少您嘗試使用外部連接維護的結果集;因此您應該在(獨佔)內部聯接之後執行包含(外部)聯接;否則外連接是毫無意義的。 – Triynko 2011-05-09 17:21:48

18

我不認爲任何人都很認真,或解釋得很好。你正在將'舊風格'(theta)和'新風格'(ANSI)聯合起來,我強烈懷疑它們是以你不期望的方式分組的。看看這樣說:

SELECT * FROM a, b JOIN c ON a.x = c.x 

好像是說

SELECT * FROM a, (b JOIN c on a.x = c.x) 

,其中括號內的東西代表了一堆表合併成一個虛擬的表,要與θ-加入反對加入上'一個'。很明顯,'a'表不能成爲連接的一部分,因爲它只能在後面加入。反過來,你正在做

SELECT * FROM b, (a JOIN c on a.x = c.x) 

這是完全可以理解和如此好。我不確定爲什麼你不使用ANSI加入語法雖然,似乎有點奇怪(並且對那些必須維護它的人是殘酷的!)

+0

這必須是發生了什麼事情。我懷疑這個實現並沒有期望人們混合使用這個語法,即使他們這樣做了,也沒有定義混合語法行爲的標準。 – 2008-10-09 13:43:57