如果查询中包含内连接,为啥左连接会变成内连接?
Posted
技术标签:
【中文标题】如果查询中包含内连接,为啥左连接会变成内连接?【英文标题】:Why left join turns into inner join if inner join is included in the query?如果查询中包含内连接,为什么左连接会变成内连接? 【发布时间】:2015-10-18 19:48:27 【问题描述】: 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 = 整个查询是内连接的。
我找到的唯一解决方案是在左连接中加入子查询,但是,我不明白它有什么不同。
【问题讨论】:
【参考方案1】:由于连接嵌套的影响,这是数据库实现中的常见行为。一系列左连接后跟内连接(或 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 * 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)。
【讨论】:
【参考方案2】:对于您的第一个查询,左连接首先发生,结果与下一个表 (ctbl) 执行内连接。
与第二个查询一样,内部联接首先发生,结果与您的第一个表 (atbl) 保持联接。希望这个答案
【讨论】:
好的。如果左连接首先发生,它仍然必须显示 TblA 的所有结果。无论如何,将整个查询变成左连接或像第二个那样进行子查询连接更好? 不,一旦发生左连接,结果将被视为单个新表。该表与第三个表执行内连接。因此,结果值将与左连接和第三个表的结果值相匹配。【参考方案3】:您仍然有一个 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 之间的 INNER JOIN] 之间进行 LEFT JOIN。请注意 atbl 和 btbl 之间的条件是最后一个条件,我特别标识了 INNER JOIN 一点,以使其更加明显它是嵌套的。
希望对你有帮助。
【讨论】:
以上是关于如果查询中包含内连接,为啥左连接会变成内连接?的主要内容,如果未能解决你的问题,请参考以下文章
SQL查询中左连接之后的所有连接是不是也必须是左连接?为啥或者为啥不?