2017-09-05 34 views
3

我遇到一個存儲過程,其中包含一些我發現混淆閱讀的語法。我希望有人能夠幫助解釋JOINS中'ON'關鍵字的多重用法(請參閱下面的一般示例)。我無法找到明確的答案和例子,爲什麼會使用這種方法。TSQL加入使用多個'ON'關鍵字

SELECT * 
FROM rc rc 
RIGHT OUTER JOIN etc 
INNER JOIN CR cr 
INNER JOIN cre cre ON cr.x = cre.x 
INNER JOIN ca ca ON cr.ID = ca.ID ON etc.ETCID = cre.ETCID 
LEFT OUTER JOIN cred cred ON cre.CRID = cred.CRID 
LEFT OUTER JOIN SC SC ON cred.ID = SC.ID 
RIGHT OUTER JOIN ec ec ON cred.ID = ec.ID 
LEFT OUTER JOIN ecc ecc ON cred.ID = ecc.ID 
LEFT OUTER JOIN hcc hcc ON cred.ID = hcc.ID ON rc.ID = cred.ID 
+1

您或者錯誤地轉錄了SQL語句,或者這不是T-SQL。你不能寫:ON t2.ID = t3.ID ON t2.ID = t1.ID',因爲它甚至不是有效的。如果在其他數據庫管理系統上甚至有效,我會感到驚訝。 – Icarus

+2

查詢中前面可能有一個連接沒有on子句,您的示例已被省略。像https://dba.stackexchange.com/a/125423/3690 –

+0

我的道歉,考慮到評論,我反而複製/粘貼連接並刪除表和列的名稱。 – Brien

回答

2

時退房FROM條款上this page的語法。我已經轉載了幾個相關的位位置:相關的查詢

[ FROM { <table_source> } [ ,...n ] ] 

<table_source> ::= 
{ 
    table_or_view_name [ [ AS ] table_alias ] 
     [ <tablesample_clause> ] 
     [ WITH (<table_hint> [ [ , ]...n ]) ] 
    | <some options omitted here> 
    | <joined_table> 
    | <some more options omitted here> 
} 

<joined_table> ::= 
{ 
    <table_source> <join_type> <table_source> ON <search_condition> 
    | <some options omitted here> 
} 

<join_type> ::= 
[ { INNER | { { LEFT | RIGHT | FULL } [ OUTER ] } } [ <join_hint> ] ] 
JOIN 

的幾點在你原來的問題:

  1. 所示<joined_table> -actually唯一一個我第一種形式已經顯示 - 以ON子句結尾,並且允許在其<join_type>和其ON子句之間的任何<table_source>

  2. <joined_table>本身是一個有效的形式<table_source>

  3. 因此合法的巢一個<joined_table>的另一個內,在這種情況下,內<joined_table>ON子句將緊跟由外<joined_table>ON子句。我認爲這就是你在查詢中看到的。

爲了驗證,我可以複製你的結果,我創建了適當的內存中的表,並將其代入原始查詢得到:

declare @rc table (id bigint); 
declare @etc table (etcid bigint); 
declare @cr table (x bigint, id bigint); 
declare @cre table (x bigint, etcid bigint, crid bigint); 
declare @ca table (id bigint); 
declare @cred table (crid bigint, id bigint); 
declare @sc table (id bigint); 
declare @ec table (id bigint); 
declare @ecc table (id bigint); 
declare @hcc table (id bigint); 

SELECT * 
FROM 
    @rc rc 
    RIGHT OUTER JOIN 
     @etc etc/*added*/ 
     INNER JOIN 
      @CR cr 
      INNER JOIN @cre cre 
      ON cr.x = cre.x 
      INNER JOIN @ca ca 
      ON cr.ID = ca.ID 
     ON etc.ETCID = cre.ETCID 
     LEFT OUTER JOIN @cred cred 
     ON cre.CRID = cred.CRID 
     LEFT OUTER JOIN @SC SC 
     ON cred.ID = SC.ID 
     RIGHT OUTER JOIN @ec ec 
     ON cred.ID = ec.ID 
     LEFT OUTER JOIN @ecc ecc 
     ON cred.ID = ecc.ID 
     LEFT OUTER JOIN @hcc hcc 
     ON cred.ID = hcc.ID 
    ON rc.ID = cred.ID 

只有三個原始查詢之間的差異和我的,他們都不應該影響它是如何工作的:

  1. 我用我的等效內存表名替換您的原始表名。

  2. 我將原始查詢中的etc更改爲@etc etc,給出@etc表的別名。

  3. 我改變了格式,以便每個ON子句直接位於相應的JOIN的下面,以便有希望地說明與什麼相關的內容。

下面是我的一些額外的視覺輔助編輯器的截圖:注意每個藍色滿足上面給出的<joined_table>的定義概括的大表情。綠色箭頭將奇怪的ON子句與其對應的連接匹配。

Query illustration

所以,是的,它是合法的語法,但沒有,我想不出任何理由,爲什麼你預期的要做到這一點。如果您打算將一組表添加到另一個表中,則可用的替代方法很少,例如子查詢或common table expression

+0

優秀的標記!我相信這樣做是因爲在RIGHT OUTER JOIN之後的INNER JOIN有效地使RIGHT OUTER JOIN成爲INNER JOIN。因此,您將ON子句移到最後,並讓優化程序最後考慮OUTER JOIN。 –

1

使用1x和使用AND之後在技術上是相同的。執行沒有區別。就我個人而言,我從來沒有見過有人寫過多個ON

SELECT * 
FROM table1 t1 
INNER JOIN table2 t2 ON t1.ID = t2.ID 
LEFT OUTER JOIN table3 t3 ON t2.ID = t3.ID AND t2.ID = t1.ID 
+2

你還沒有看到它,因爲它不是有效的t-sql!你不能做't2.ID = t3.ID ON t2.ID = t1.ID' – Icarus

+0

@BrienFoss它不起作用。幾秒鐘內看到我的答案。 – Icarus

0

您要麼不正確地轉錄SQL語句,要麼這不是T-SQL。你不能寫:ON t2.ID = t3.ID ON t2.ID = t1.ID甚至不是有效的。如果在其他數據庫管理系統上甚至有效,我會感到驚訝。

你能做些什麼,雖然是這樣的:

SELECT * 
FROM table1 t1 
INNER JOIN table2 t2 ON t1.ID = t2.ID 
LEFT OUTER JOIN table3 t3 ON t2.ID = t3.ID 
AND /*AND, NOT ON*/ 
t2.ID = t1.ID 

換句話說,你可以做一個JOIN迫使多個列的比賽,但你不能做一個JOIN你寫它上面的方法。

+0

Downvoting,因爲它顯然是錯誤的:如果實際創建OP中引用的所有表,您會發現SQL Server * does *實際上按寫入的方式執行查詢。我還沒有解開它究竟是如何做到的,但不知怎的,這是一種公認​​的非常混亂的語法。 –

+0

@JoeFarrell不,它不會執行它。這不是有效的語法。閱讀BNF的T-SQL FFS! – Icarus

+0

@JoeFarrell這個答案是在編輯問題之前編寫的。 Q中的原始代碼是無效的,因爲必須有和連接一樣多的'on'子句,並且它有三個子句和兩個連接。關於「解開」在評論中看到我的鏈接。 –

2

實際上,JOIN不僅加入表或視圖,而且還加入其他聯合操作的結果。這會導致ON關鍵字不直接跟隨聯接的表名稱。

括號表示加入連接結果:

SELECT * 
FROM rc rc 
RIGHT OUTER JOIN 
[ etc 
    INNER JOIN CR 
    [ cr 
     INNER JOIN cre cre ON cr.x = cre.x 
     INNER JOIN ca ca ON cr.ID = ca.ID 
    ] ON etc.ETCID = cre.ETCID 
    LEFT OUTER JOIN cred cred ON cre.CRID = cred.CRID 
    LEFT OUTER JOIN SC SC ON cred.ID = SC.ID 
    RIGHT OUTER JOIN ec ec ON cred.ID = ec.ID 
    LEFT OUTER JOIN ecc ecc ON cred.ID = ecc.ID 
    LEFT OUTER JOIN hcc hcc ON cred.ID = hcc.ID 
] ON rc.ID = cred.ID