简体   繁体   English

SQL Server:加入新语法(ANSI与非ANSI SQL JOIN语法)

[英]SQL Server : joins new syntax(ANSI vs. non-ANSI SQL JOIN syntax)

I have tried to convert old MS sql join syntax to new join syntax but number of rows in the results not matching. 我试图将旧的MS sql连接语法转换为新的连接语法,但结果中的行数不匹配。

Original SQL: 原始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

Converted SQL: 转换后的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

Findings 发现

Results are same on both original SQL and modified SQL upto joining of 3 tables but when joining the fourth table (TableD) to the modified SQL, the number of rows returned is different. 原始SQL和修改后的SQL的结果相同(最多3个表的连接),但是将第四个表(TableD)连接到修改的SQL时,返回的行数不同。

The order of fields within predicates is important when using SQL Server's (deprecated) proprietary ANSI 89 join syntax *= or =* 使用SQL Server(不建议使用)专有ANSI 89连接语法*==*时,谓词中字段的顺序很重要=*

So while 所以当

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

Is exactly the same as 完全一样

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

The eqivalent 等效

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

Is not the same as 与...不同

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

This last query's ANSI 92 equivalent would be 最后一个查询的ANSI 92等效项为

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

Or if you dislike RIGHT JOIN as much as I do you would probably write: 或者,如果您像我一样不喜欢RIGHT JOIN ,那么您可能会写:

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

So actually the equivalent query in ANSI 92 join syntax would involve starting with TableA, TableC and TableD (since these are the leading fields in the original WHERE Clause). 因此,实际上,ANSI 92连接语法中的等效查询将涉及以TableA,TableC和TableD开头(因为这些是原始WHERE子句中的前导字段)。 Then since there is no direct link between the three, you end up with a cross join 然后,由于这三个之间没有直接链接,因此最终会产生交叉连接

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;

This is the equivalent rewrite, and explans the difference in the number of rows 这是等效的重写,并解释了行数的差异

WORKING EXAMPLE 工作实例

Needs to be run on SQL Server 2008 or earlier with compatibility level 80 or less 需要在兼容级别为80或更低的SQL Server 2008或更早版本上运行

-- 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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM