2010-09-23 197 views
16

我有三個表:R,S和P.SQL連接三個表,連接優先

表R通過外鍵連接S;有應該是S中至少一個的記錄,所以我可以加入:

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 

如果有S中的任何記錄,那麼我沒有得到任何行,這很好。

然後表信息系統S有P連接,其中的記錄爲P可能會或可能不會出現,並與S.

加入

所以我做

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 
    LEFT JOIN P ON (P.id = S.fkp) 

,如果我想要第二個連接被捆綁與S不是R,就像如果我可以使用括號:

SELECT 
     * 
    FROM 
     R 
    JOIN (S ON (S.id = R.fks) JOIN P ON (P.id = S.fkp)) 

或者是,R,S和P之間的乘積的已經是一個自然的行爲?

+0

你能否解釋一下這部分「如果我想第二個連接被束縛不是以R」 眼下表的連接爲R帶S加入,然後留下P. – 2010-09-23 16:05:37

+0

加入我試着瞭解是否有一種方法可以優先考慮連接,就像它們是算術運算符一樣。如果這在連接條件中是隱含的,我不明白。 – vulkanino 2010-09-23 16:08:21

+0

給我們一個你希望實現的與普通聯接不同的數據例子,我們可以更好地告訴你該怎麼做。派生表可能做你想做的事情,但我不確定你想要什麼。 – HLGEM 2010-09-23 17:25:29

回答

26

所有類型的外連接和正常連接處於相同的優先級類別,並且運算符在查詢的給定嵌套級別上從左到右生效。您可以將連接表達式放在括號的右側,使其首先生效;請記住,您必須移動現在位於您放置夥伴的聯接之外的聯接的ON子句。

(PostgreSQL的例子)

SELECT * FROM a LEFT JOIN b ON (a.id = b.id) JOIN c ON (b.ref = c.id);

的AB加入生效第一,但我們可以強制BC聯接到做第一生效:

SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);

通常你可以通過移動連接並改變外部連接方向來表示相同的事物而無需額外的括號,例如

SELECT * FROM b JOIN c ON (b.ref = c.id) RIGHT JOIN a ON (a.id = b.id);

+1

澄清:所有加入運算符具有相同的優先級,並且都具有從左到右的關聯性。這是減法( - )和除法(/)操作符幾乎在所有編程語言中工作的方式。改變操作數的順序對其「優先級」(SQL語法的一個方面而不是任何情況下的操作數)沒有影響。這樣做會利用連接的從左到右的關聯性來實現組合連接的所需語義。但它不會改變表達中任何事物的優先性和關聯性 - 只會改變其解釋的上下文。 – 2016-03-24 19:37:37

+0

夠公平的。什麼是第二個詞,表達一個運算符在另一個運算符的影響之前的效果,但不是因爲已經採用了這個效果而沒有優先權? – rakslice 2016-03-26 20:07:46

+0

換句話說。另外,儘管我不喜歡用別人的專業詞彙來表達它的詞典定義(不,我不知道),但真正研究我的齒輪的東西就像「結合性」,其中專業術語是已被佔用的數學術語由計算世界。 – rakslice 2016-03-26 20:28:20

1

第二次加入與S相連,如您明示狀態JOIN P ON (P.id = S.fkp) - 在連接中沒有引用來自R的列。

+0

好的,但一般來說,沒有辦法優先考慮連接? – vulkanino 2010-09-23 16:04:43

+0

我不認爲SQL以您想的方式工作。 Paul Spangle的答案描述了SQL如何「思考」連接。 – 2010-09-23 16:16:16

2

當你加入第三個表,您的第一個查詢

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 

就像是一個派生表到你所參加的第三個表。因此,如果R JOIN S不產生任何行,那麼加入P將永遠不會產生任何行(因爲您試圖連接到空表)。

所以,如果你正在尋找優先規則,那麼在這種情況下,它只是使用LEFT JOIN而不是JOIN來設置。

但是,我可能會誤解你的問題,因爲如果我正在編寫查詢,我會換用SR。例如。

SELECT 
     * 
    FROM 
     S 
    JOIN R ON (S.id = R.fks) 
+0

考慮我必須加入3個表格,而不是2個。 – vulkanino 2010-09-23 16:20:14

+1

它只是從左到右工作。我能想到的唯一方法是將一個完整的派生表放在一些括號中。 – 2010-09-23 16:30:15

1

連接沒有優先權,它是關聯操作。舊的逗號分隔語法清楚地表明瞭,新的語法(大概是爲了模仿關係代數而熟悉的)令人困惑。然而,外連接(單獨使用或與常規連接一起使用)不具有關聯性。

+3

考慮到OP詢問LEFT JOINS,JOINS關聯的陳述很容易引起誤解。 – Taemyr 2014-02-28 10:19:58

0
with a as (select 1 as test union select 2) 
select * from a left join 
a as b on a.test=b.test and b.test=1 inner join 
a as c on b.test=c.test 
go 
with a as (select 1 as test union select 2) 
select * from a inner join 
a as b on a.test=b.test right join 
a as c on b.test=c.test and b.test=1 

理想情況下,我們希望的是,上述兩個查詢是相同的。然而,它們不是 - 所以任何人都說在所有情況下都可以用左連接代替正確的連接是錯誤的。只有使用正確的連接才能獲得所需的結果。

+1

右連接與這個問題無關,沒有人說他們是一樣的。 – Hogan 2016-07-29 17:48:09