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

时间:2015-07-28 10:06:33

标签: sql-server tsql left-join inner-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

Sql results for both queries

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

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

3 个答案:

答案 0 :(得分: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

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

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

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)。

答案 1 :(得分:0)

使用第一个查询时,左连接首先发生,结果与下一个表(ctbl)执行内连接。

与第二个查询一样,内连接首先发生,结果与第一个表(atbl)保持连接。希望这个答案

答案 2 :(得分:0)

你仍然有LEFT JOIN,但你在ctbl上进行INNER JOIN,它会过滤掉所有数据。看看你的陈述,我认为你在LEFT JOIN中寻找嵌套的内部联系:

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

这样,你在atbl和[btbl和ctbl之间的INNER JOIN]之间进行LEFT JOIN。请注意atbl和btbl之间的条件是最后一个条件,并且我特别注意了INNER JOIN以使其更明显它是NESTED。

希望它有所帮助。

相关问题