2016-03-03 154 views
1

我試圖將舊的MS SQL連接語法轉換爲新的連接語法,但結果中的行數不匹配。SQL Server:連接新語法(ANSI與非ANSI SQL JOIN語法)

原來的SQL:

select 
    b.Amount 
from 
    TableA a, TableB b,TableC c, TableD d 
where 
    a.inv_no *= b.inv_no and 
    a.inv_item *= b.inv_item and 
    c.currency *= b.cash_ccy and 
    d.tx_code *= b.cash_receipt 

轉換SQL:

SELECT 
    b.AMOUNT 
FROM 
    (TableA AS a 
LEFT OUTER JOIN 
    TableB AS b ON a.INV_NO = b.INV_NO 
       AND a.inv_item = b.inv_item 
LEFT OUTER JOIN 
    TableC AS c ON c.currency = b.cash_ccy) 
LEFT OUTER JOIN 
    TableD as d ON d.tx_code = b.cash_receipt 

發現

結果是在兩個原來的SQL相同和改性SQL高達接合3代表的但在加入時第四個表(TableD)到已修改的SQL,返回的行數是不同的。

+0

刪除括號。 –

+0

圍繞前兩個'LEFT OUTER JOIN'的括號*'(...)'*是什麼? – Lankymart

+1

'*'被放在舊式連接的強制性一面。所以看起來像一些連接必須被顛倒。 –

回答

5

謂詞中字段的順序使用SQL Server的(不建議使用)專有的ANSI 89聯接語法*==*

時很重要,而

SELECT * 
FROM TableA AS A 
     LEFT JOIN TableB AS B 
      ON A.ColA = B.ColB; 

是完全一樣的

SELECT * 
FROM TableA AS A 
     LEFT JOIN TableB AS B 
      ON B.ColB = A.ColA;  -- NOTE ORDER HERE 

當量

SELECT * 
FROM TableA AS A, TableB AS b 
WHERE A.ColA *= B.ColB; 

是不一樣的

SELECT * 
FROM TableA AS A, TableB AS b 
WHERE B.ColA *= A.ColB; 

這最後一個查詢的ANSI 92相當於將

SELECT * 
FROM TableA AS A 
     RIGHT JOIN TableB AS B 
      ON A.ColA = B.ColB; 

或者,如果你不喜歡RIGHT JOIN我一樣多,你可能會寫:

SELECT * 
FROM TableB AS B 
     LEFT OUTER JOIN TableA AS A 
      ON B.ColB = A.ColA; 

所以實際上,ANSI 92連接語法中的等效查詢將涉及從TableA,Tab開始leC和TableD(因爲這些是原始WHERE子句中的主要字段)。然後,因爲三者之間沒有直接的聯繫,你結束了一個交叉連接

SELECT b.Amount 
FROM TableA AS a  
     CROSS JOIN TableD AS d 
     CROSS JOIN TableC AS c 
     LEFT JOIN TableB AS B 
      ON c.currency = b.cash_ccy 
      AND d.tx_code = b.cash_receipt 
      AND a.INV_NO = b.INV_NO 
      AND a.inv_item = b.inv_item; 

這相當於重寫,並植體中的行數之差

工作例

需要SQL Server 2008上與兼容級別運行或更早的80個或更少

-- SAMPLE DATA -- 
CREATE TABLE #TableA (Inv_No INT, Inv_item INT); 
CREATE TABLE #TableB (Inv_No INT, Inv_item INT, cash_ccy INT, cash_receipt INT, Amount INT); 
CREATE TABLE #TableC (currency INT); 
CREATE TABLE #TableD (tx_code INT); 

INSERT #TableA (inv_no, inv_item) VALUES (1, 1), (2, 2); 
INSERT #TableB (inv_no, inv_item, cash_ccy, cash_receipt, Amount) VALUES (1, 1, 1, 1, 1), (2, 2, 2, 2, 2); 
INSERT #TableC (currency) VALUES (1), (2), (3), (4); 
INSERT #TableD (tx_code) VALUES (1), (2), (3), (4); 

-- ORIGINAL QUERY(32 ROWS) 
SELECT 
    b.Amount 
FROM 
    #TableA a, #TableB b,#TableC c, #TableD d 
WHERE 
    a.inv_no *= b.inv_no and 
    a.inv_item *= b.inv_item and 
    c.currency *= b.cash_ccy and 
    d.tx_code *= b.cash_receipt 

-- INCORRECT ANSI 92 REWRITE (2 ROWS) 
SELECT b.AMOUNT 
FROM #TableA AS a 
     LEFT OUTER JOIN #TableB AS b 
      ON a.INV_NO = b.INV_NO 
      and a.inv_item = b.inv_item 
     LEFT OUTER JOIN #TableC AS c 
      ON c.currency = b.cash_ccy 
     LEFT OUTER JOIN #TableD as d 
      ON d.tx_code = b.cash_receipt; 


-- CORRECT ANSI 92 REWRITE (32 ROWS) 
SELECT b.Amount 
FROM #TableA AS a   
     CROSS JOIN #TableD AS d 
     CROSS JOIN #TableC AS c 
     LEFT JOIN #TableB AS B 
      ON c.currency = b.cash_ccy 
      AND d.tx_code = b.cash_receipt 
      AND a.INV_NO = b.INV_NO 
      AND a.inv_item = b.inv_item; 
+0

這個查詢可以簡化成一些不那麼難看的東西嗎? –

+1

@JoePhilllips原來的查詢實際上更像是一種瘋狂的問題。你有一種想要從頭開始重寫整個事情,理解原始查詢試圖做什麼,我們不太瞭解的東西。這基本上是一個「機器翻譯」 - 它產生相同的結果,但它有點難看。 – Luaan