查询中包含inner join,为什么left join会变成inner join?

Why left join turns into inner join if inner join is included in the query?

    IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Atbl')
 DROP TABLE Atbl

CREATE TABLE ATbl
 (
    Id int unique,
    AName varchar(20),
 )

 GO

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Btbl')
    DROP TABLE Btbl

CREATE TABLE BTbl
 (
    Id int unique,
    BName varchar(20),
    ATblId int
 )

GO

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Ctbl')
    DROP TABLE Ctbl

CREATE TABLE CTbl
 (
    Id int unique,
    CName varchar(20),
    BTblId int
 )

GO

TRUNCATE TABLE Atbl
TRUNCATE TABLE Btbl
TRUNCATE TABLE Ctbl


INSERT INTO Atbl VALUES (1, 'Name1')
INSERT INTO Atbl VALUES (2, 'Name2')
INSERT INTO Atbl VALUES (3, 'Name3')

INSERT INTO Btbl VALUES (1, 'Name1', 2)
INSERT INTO Btbl VALUES (2, 'Name2', 3)

INSERT INTO Ctbl VALUES (1, 'Name2', 2)

select * from atbl
left join btbl on btbl.atblid=atbl.id
inner join ctbl on ctbl.btblid=btbl.id

select * from atbl
left join 
(select btbl.id, btbl.atblid from btbl
inner join ctbl on ctbl.btblid=btbl.id) a
on atbl.id=a.atblid

为什么查询中的一个内连接将所有查询变成内连接。 第一个查询连接 TblA -(LEFT JOIN)-> TblB -> (INNER JOIN) -> TblC = 整个查询是内连接的。

我找到的唯一解决方案是在左连接中加入子查询,但是,我不明白它有何不同。

对于您的第一个查询,左连接首先发生,结果与下一个 table (ctbl) 执行内连接。

与第二个查询一样,内部联接首先发生,结果与您的第一个 table (atbl) 左联接。希望这个答案

由于连接嵌套的影响,这是数据库实现中的常见行为。一系列左连接后跟一个内连接(或一个 CROSS APPLY 而不是一个 OUTER APPLY)将有这个结果。

为避免这种情况,您已经想到了解决方案:

select * from atbl
left join 
    (select btbl.id, btbl.atblid 
        from btbl
        inner join ctbl on ctbl.btblid=btbl.id) a
        on atbl.id=a.atblid

这是一个不相关的子查询,因为您没有在括号内引用 ATBL - 这意味着引擎可以 select 一个相当好的连接策略,或者计算整个子查询一次而不是行-逐行。

另一种选择是将所有 table 连接更改为左连接:

select * from atbl
    left join btbl on btbl.atblid=atbl.id
        left join ctbl on ctbl.btblid=btbl.id
WHERE
     -- Rows where the first LEFT is not satisfied, or BOTH are satisfied.
     (btbl.atblid IS NULL OR ctbl.btblid IS NOT NULL)

然后您可以使用 WHERE 子句来过滤从 B 开始的连接都没有被命中的位置(即我没有找到 B 或我同时找到了 B 和 C)。

你仍然有一个 LEFT JOIN 那里但是你在 ctbl 上做了 INNER JOIN 过滤掉所有数据。查看您的声明,我认为您正在寻找 LEFT JOIN 中的 NESTED INNER JOIN:

SELECT * 
FROM    atbl
        LEFT JOIN btbl 
            INNER JOIN ctbl 
                ON ctbl.btblid=btbl.id
            ON btbl.atblid=atbl.id

这样,您就可以在 atbl 和 [ btbl 和 ctbl 之间的内连接] 之间进行左连接。请注意 atbl 和 btbl 之间的条件是最后一个条件,我特别将 INNER JOIN 标识得更多一些,以使其更明显它是 NESTED。

希望对您有所帮助。