如果查询中包含内连接,为什么左连接变成内连接?

sch*_*dly 5 t-sql sql-server inner-join left-join

    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
Run Code Online (Sandbox Code Playgroud)

两个查询的 Sql 结果

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

我发现的唯一解决方案是在 left join 中加入子查询,但是,我不明白它有什么不同。

小智 2

由于连接嵌套的影响,这是数据库实现中的常见行为。一系列左连接后跟一个内部连接(或一个 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
Run Code Online (Sandbox Code Playgroud)

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

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

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)
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用 WHERE 子句来过滤从 B 开始的连接均未命中的位置(即,我没有找到 B,或者我发现了 aa B 和 a C)。