在我在项目中找到的一些遗留代码中进行一些重构。这适用于MSSQL。问题是,我无法理解为什么我们使用左右混合连接并将一些连接条件整理在一起。
我的问题是:这不会在某些地方创建隐式内部联接而在其他地方隐式完全联接吗?
我是学校,几乎任何东西都可以使用左(和内/完)或恰到好处(和内/完)来写,但这是因为我喜欢尽可能保持简单。
顺便说一句,我们将所有这些内容转换为在oracle数据库上工作,所以也许有些优化规则与Ora的工作方式不同?
例如,这是其中一个查询的FROM部分:
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
答案 0 :(得分:4)
我要做的一件事是确保在弄清楚这一点之前知道你期望得到什么结果。不想“修复”它并返回不同的结果。老实说,如果查询设计不合理,我现在不确定你是否真的得到了正确的结果。
对我来说,这看起来像是某人随着时间推移甚至可能从内部联接开始的事情,意识到它们不会工作并改变到外部联接但不想打扰更改查询中引用表的顺序。< / p>
出于维护目的,我特别关注的是将ON子句放在要连接的表旁边,以及将所有连接转换为左连接而不是混合左右连接。将表4和表3的ON子句放在表9旁边对我来说毫无意义,并且应该导致混淆查询应该实际返回的内容。您可能还需要更改连接的顺序才能转换为所有左连接。我个人更喜欢从其他人加入的主表开始(似乎是table2),然后从那里开始沿着食物链工作。
答案 1 :(得分:1)
它可能被转换为使用所有LEFT连接:我正在寻找并移动每个RIGHT中的右侧桌面以超过所有现有的LEFT,然后你可能能够然后将每个RIGHT联接转换为LEFT联接。我不确定你会在幕后得到任何FULL连接 - 如果查询看起来像是这样,它可能是这个特定查询的怪癖而不是SQL Server“规则”:你提供的查询确实如此似乎是以一种相当混乱的方式混合起来。
对于Oracle优化 - 这当然是可能的。我自己没有甲骨文的经验,但是对于在这方面知识渊博的朋友说,甲骨文(不知道是什么版本)是关于谓词顺序的繁琐。例如,使用SQL Server,您可以编写路径子句,以便列以任何顺序使用索引,但是对于Oracle,您最终必须按照它们在索引中出现的顺序指定列,以获得最佳性能与索引。如上所述 - 不知道新的Oracle是否属于这种情况,但旧的情况就是如此(显然)。
这是否解释了这个特殊的结构,我不能说。如果多年来这些代码发生变化,那么它可能只是一个不太理想的代码,而且它正在乞求清理。
答案 2 :(得分:1)
LEFT
和RIGHT
加入是纯语法糖。
只有通过切换集合,任何LEFT JOIN
都可以转换为RIGHT JOIN
。
前 - 9i
Oracle
使用了此构造:
WHERE table1.col(+) = table2.col
,(+)
此处表示可以为空的列,LEFT
和RIGHT
联接可以通过切换来模拟:
WHERE table1.col = table2.col(+)
在MySQL
中,没有FULL OUTER JOIN
,需要模拟它。
通常这样做是这样的:
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
,复制JOIN
并将LEFT
替换为RIGHT
比交换表格更方便。
请注意,在SQL Server
计划中,Hash Left Semi Join
和Hash Right Semi Join
是不同的运营商。
对于这样的查询:
SELECT *
FROM table1
WHERE table1.col IN
(
SELECT col
FROM table2
)
,Hash Match (Left Semi Join)
哈希table1
并在运行时从哈希表中删除匹配的元素(这样它们不能匹配多次)。
Hash Match (Right Semi Join)
哈希table2
并在构建哈希表时从哈希表中删除重复的元素。
答案 3 :(得分:0)
我可能在这里遗漏了一些东西,但是LEFT和RIGHT联接之间的唯一区别是源表的编写顺序,因此具有多个LEFT连接或多个RIGHT连接与混合没有什么不同。与所有LEFT / RIGHT相比,可以轻松实现与FULL OUTER的等效,而不是混合,最好的?
答案 4 :(得分:0)
我们在同一个查询中有一些LEFT OUTER JOIN
和RIGHT OUTER JOIN
个。通常这样的查询很大,已经存在了很长时间,可能在一开始就写得很糟糕并且很少得到维护。我假设引入RIGHT OUTER JOIN
作为维护查询的一种方法,而不会在重构查询时承担不可避免的风险。
我认为大多数SQL编码器最容易使用所有LEFT OUTER JOIN
,这可能是因为FROM
子句以英语方式从左到右读取。
我自己使用RIGHT OUTER JOIN
的唯一时间是在基于现有查询编写新查询时(无需重新发明轮子),我需要将INNER JOIN
更改为{{ 1}}。为了能够使用OUTER JOIN
而不是更改JOIN
子句中FROM
的顺序,我会使用LEFT OUTER JOIN
而不会打扰我。这是非常罕见的。如果原始查询有RIGHT OUTER JOIN
s,那么我最终会混合LEFT OUTER JOIN
- 和LEFT
s,这也不会打扰我。但是,我还没有发生过。
请注意,对于不支持RIGHT OUTER JOIN
的Access数据库引擎等SQL产品,一种解决方法是在同一查询中FULL OUTER JOIN
UNION
和LEFT OUTER JOIN
答案 5 :(得分:0)
最重要的是,这是一个格式很差的SQL语句,应该重写。许多ON子句远离它们的JOIN语句,我不确定它是否是有效的SQL。
为了清楚起见,我将使用所有LEFT JOINS(而不是RIGHT)重写查询,并在相应的JOIN子句下面找到using语句。否则,这有点像火车残骸,并且混淆了查询的目的,在未来的修改过程中更容易发生错误。
这不会创造隐含的内在 加入某些地方并隐含充分 加入其他人?
也许您假设这是因为您没有看到某些联接的ON子句,例如RIGHT OUTER JOIN Table4
,但它位于下方,ON Table4.T7FK= Table7.T7PK
。我没有看到任何隐式内连接,如果有像WHERE Table3.T3PK is not null
这样的WHERE子句,可能会发生。
您提出这样的问题这一事实证明了查询的不透明性。
答案 6 :(得分:0)
要回答此问题的另一部分尚未回答,此查询格式奇怪的原因是它可能是使用SQL Management Studio中的查询设计器构建的。赠与是组合的ON子句,在提到表之后会发生很多行。基本上,表格会在构建查询窗口中添加,即使连接事物的方式有利于移动表格,也就是说,并保持所有连接在某个方向上,所以保持顺序。