Jus*_* R. 16 sql algorithm join subquery relational-model
是否存在将SQL子查询转换为连接的通用过程或算法,反之亦然?也就是说,是否有一组排版操作可以应用于语法正确的SQL查询语句,其中包含一个子查询,该子查询导致函数等效语句没有子查询?如果是这样,它们是什么(即算法是什么),在什么情况下它们不适用?
OMG*_*ies 24
将子查询转换为JOIN可以非常简单:
IN
条款 FROM TABLE_X x
WHERE x.col IN (SELECT y.col FROM TABLE_Y y)
Run Code Online (Sandbox Code Playgroud)
...可以转换为:
FROM TABLE_X x
JOIN TABLE_Y y ON y.col = x.col
Run Code Online (Sandbox Code Playgroud)
您的JOIN标准是您直接比较的地方.
EXISTS
条款但是当你看这个EXISTS
条款时会有一些复杂的问题.EXISTS 是通常correllated,其中所述子查询是通过从子查询外部的表(多个)标准过滤.但EXISTS仅用于根据条件返回布尔值.
FROM TABLE_X x
WHERE EXISTS (SELECT NULL
FROM TABLE_Y y
WHERE y.col = x.col)
Run Code Online (Sandbox Code Playgroud)
...转化:
FROM TABLE_X x
JOIN TABLE_Y y ON y.col = x.col
Run Code Online (Sandbox Code Playgroud)
由于布尔值,结果集中存在更多行出现的风险.
SELECT
在SELECT子句中这些应该总是在偏见的情况下改变:
SELECT x.*,
(SELECT MAX(y.example_col)
FROM TABLE_Y y
WHERE y.col = x.col)
FROM TABLE_X x
Run Code Online (Sandbox Code Playgroud)
你现在可能注意到了一个模式,但是对于内联视图示例我做了一点点不同:
SELECT x.*,
z.mc
FROM TABLE_X x
JOIN (SELECT y.col, --inline view within the brackets
MAX(y.example_col) 'mc'
FROM TABLE_Y y
GROUP BY y.col) z ON z.col = x.col
Run Code Online (Sandbox Code Playgroud)
关键是确保内联视图结果集包括连接所需的列以及列.
LEFT JOIN
小号您可能已经注意到我没有任何LEFT JOIN示例 - 只有在子查询中的列使用NULL测试时才会这样做(COALESCE
这几天几乎任何数据库,Oracle NVL
或NVL2
MySQL IFNULL
,SQL Server ISNULL
等等):
SELECT x.*,
COALESCE((SELECT MAX(y.example_col)
FROM TABLE_Y y
WHERE y.col = x.col), 0)
FROM TABLE_X x
Run Code Online (Sandbox Code Playgroud)
转化:
SELECT x.*,
COALESCE(z.mc, 0)
FROM TABLE_X x
LEFT JOIN (SELECT y.col,
MAX(y.example_col) 'mc'
FROM TABLE_Y y
GROUP BY y.col) z ON z.col = x.col
Run Code Online (Sandbox Code Playgroud)
我不确定这是否能满足您的印刷需求,但希望我已经证明关键在于确定JOIN标准是什么.一旦知道所涉及的列,就会知道所涉及的表格.
Rob*_*ley 10
这个问题依赖于关系代数的基本知识.你需要问问自己正在进行什么样的连接.例如,LEFT ANTI SEMI JOIN就像一个WHERE NOT EXISTS子句.
某些连接不允许重复数据,有些不允许删除数据.其他人允许额外的字段可用.我在我的博客中讨论了这个问题,网址是http://msmvps.com/blogs/robfarley/archive/2008/11/09/join-simplification-in-sql-server.aspx
此外,请不要觉得你需要在JOIN中做所有事情.查询优化器应该为您处理所有这些,并且您经常可以更难以维护这种方式查询.您可能会发现自己使用了一个广泛的GROUP BY子句,并且有一个有趣的WHERE .. IS NULL过滤器,它只用于断开业务逻辑与查询设计的连接.
SELECT子句中的子查询(本质上是查找)仅提供额外的字段,而不是重复或消除.因此,您需要确保在JOIN中强制执行GROUP BY或DISTINCT值,并使用OUTER JOIN来保证行为相同.
WHERE子句中的子查询永远不能复制数据,或者为SELECT子句提供额外的列,因此您应该使用GROUP BY/DISTINCT来检查它.在哪里存在类似的东西.(这是LEFT SEMI JOIN)
什么不存在(LEFT ANTI SEMI JOIN)不提供数据,并且不重复行,但可以消除...为此你需要做LEFT JOIN并寻找NULL.
但是查询优化器应该为您处理所有这些.我实际上喜欢在SELECT子句中偶尔使用子查询,因为它非常清楚我没有复制或删除行.QO可以为我整理它,但是如果我使用视图或内联表值函数,我想向那些追随我的人说清楚QO可以简化它.查看原始查询的执行计划,您将看到系统正在为您提供INNER/OUTER/SEMI连接.
你真正需要避免的事情(至少在SQL Server中)是使用BEGIN和END的函数(例如标量函数).他们可能觉得他们简化了代码,但实际上它们将在一个单独的上下文中执行,因为系统将它们视为程序性的(不可简化).
我在最近的SQLBits V会议上做过关于此类事情的会议.这是录制的,所以你应该能够在某个时刻观看它(如果你能忍受我的笑话!)