Sql 混合左连接和右连接?为什么?
在项目中发现的一些遗留代码中进行重构。这是针对MSSQL的。问题是,我不明白为什么我们使用混合的左连接和右连接,并将一些连接条件整理在一起 我的问题是:这不是在某些地方创建隐式内部联接,在其他地方创建隐式完全联接吗 我所属的学校,几乎任何东西都可以用左(和内部/完整)或右(和内部/完整)来写,但那是因为我喜欢在可能的情况下保持简单 顺便说一句,我们将所有这些东西都转换为在oracle数据库上工作,所以也许有一些优化规则在Ora上的工作方式不同 例如,下面是其中一个查询的一部分:Sql 混合左连接和右连接?为什么?,sql,join,Sql,Join,在项目中发现的一些遗留代码中进行重构。这是针对MSSQL的。问题是,我不明白为什么我们使用混合的左连接和右连接,并将一些连接条件整理在一起 我的问题是:这不是在某些地方创建隐式内部联接,在其他地方创建隐式完全联接吗 我所属的学校,几乎任何东西都可以用左(和内部/完整)或右(和内部/完整)来写,但那是因为我喜欢在可能的情况下保持简单 顺便说一句,我们将所有这些东西都转换为在oracle数据库上工作,所以也许有一些优化规则在Ora上的工作方式不同 例如,下面是其中一个查询的一部分:
FROM Table1
RIGHT OUTER JOIN Table2
ON Table1.T2FK = Table2.T2PK
LEFT OUTER JOIN Table3
RIGHT OUTER JOIN Table4
LEFT OUTER JOIN Table5
ON Table4.T3FK = Table5.T3FK
AND Table4.T2FK = Table5.T2FK
LEFT OUTER JOIN Table6
RIGHT OUTER JOIN Table7
ON Table6.T6PK = Table7.T6FK
LEFT OUTER JOIN Table8
RIGHT OUTER JOIN Table9
ON Table8.T8PK= Table9.T8FK
ON Table7.T9FK= Table9.T9PK
ON Table4.T7FK= Table7.T7PK
ON Table3.T3PK= Table4.T3PK
RIGHT OUTER JOIN ( SELECT *
FROM TableA
WHERE ( TableA.PK = @PK )
AND ( TableA.Date BETWEEN @StartDate
AND @EndDate )
) Table10
ON Table4.T4PK= Table10.T4FK
ON Table2.T2PK = Table4.T2PK
这里我可能遗漏了一些东西,但左连接和右连接之间的唯一区别是源表的写入顺序,因此具有多个左连接或多个右连接与混合没有什么区别。与混合使用相比,使用所有左/右都可以轻松地实现与完全外接的等效,这很可能被转换为使用所有左连接:我将查看并移动每个右中的右表,使其位于所有现有左表之上,然后您可以将每个右连接转换为左连接。我不确定您是否会在幕后获得任何完整连接——如果查询看起来像这样,那么这可能是此特定查询的一个怪癖,而不是SQL Server“规则”:您提供的查询似乎以一种相当混乱的方式将其混在一起 至于Oracle的优化--这当然是可能的。我本人没有Oracle方面的经验,但与一位熟悉这一领域的朋友交谈时,Oracle(不知道是什么版本)对谓词的顺序非常挑剔。例如,使用SQL Server,您可以编写自己的way子句,这样列可以按任何顺序排列,并且可以使用索引,但使用Oracle,您最终必须按列在索引中的显示顺序指定列,以便使用索引获得最佳性能。如前所述——不知道较新的甲骨文是否如此,但较旧的甲骨文确实如此(显然)
我不能说这是否解释了这种特殊的结构。如果经过多年的修改,它可能不是一个理想的代码,而清理正是它所需要的。我要做的一件事是,在处理这个问题之前,确保您知道您期望的结果。不想“修复”它并返回不同的结果。尽管老实说,对于一个设计糟糕的查询,我不确定您现在是否得到了正确的结果 对我来说,这看起来像是有人随着时间的推移所做的事情,可能最初是从内部联接开始,意识到它们不起作用,然后改为外部联接,但不想麻烦更改查询中引用表的顺序
出于维护目的,我特别关心的是将ON子句放在您要连接的表旁边,并将所有连接转换为左连接,而不是混合右连接和左连接。将表4和表3的ON子句放在表9旁边对我来说毫无意义,并且会导致对查询实际返回内容的混淆。您可能还需要更改联接的顺序,以便转换为所有左联接。就我个人而言,我更喜欢从其他人将加入的主表(看起来是表2)开始,然后从那里沿着食物链往下走。在同一个查询中,我们有一些
左外连接
s和右外连接
s。通常,这样的查询很大,已经存在很长时间,可能一开始写得很糟糕,而且很少得到维护。我假设引入了右外部联接
s作为维护查询的一种手段,而不必承担重构查询时不可避免的风险
我认为大多数SQL编码人员最容易使用allLEFT-OUTER-JOIN
s,这可能是因为FROM
子句是用英语从左到右读取的
我唯一一次使用右外部联接
是在基于现有查询编写新查询时(无需重新发明轮子),我需要将内部联接
更改为外部联接
。与其在FROM
子句中更改连接的顺序,只是为了能够使用左外部连接
,我宁愿使用右外部连接
,这不会打扰我。但这是相当罕见的。如果原始查询有左外部连接
s,那么我最终会得到左外部连接
-和右外部连接
的混合,这同样不会困扰我。但我还没遇到过
请注意,对于不支持完全外部联接的SQL产品(如Access数据库引擎),一种解决方法是在同一查询中联合左外部联接
和右外部联接。左外部联接和右外部联接是纯语法糖
任何左连接
都可以通过切换集合转换为右连接
早在9i
Oracle
使用此结构:
WHERE table1.col(+) = table2.col
,(+)
此处表示可为空的列,LEFT
和RIGHT
连接可以通过简单的切换来模拟:
WHERE table1.col = table2.col(+)
在MySQL
中,没有完全外部连接,需要对其进行仿真
通常是这样做的:
SELECT *
FROM table1
LEFT JOIN
table2
ON table1.col = table2.col
UNION ALL
SELECT *
FROM table1
RIGHT JOIN
table2
ON table1.col = table2.col
WHERE table1.col IS NULL
,并且复制连接
并将左侧
替换为右侧
,比交换表更方便
请注意,在SQL Server
计划中,Hash Left-Semi-Join
和Hash Right-Semi-Join
是不同的运算符
对于这样的查询:
SELECT *
FROM table1
WHERE table1.col IN
(
SELECT col
FROM table2
)