sql连接为维恩图
Posted
技术标签:
【中文标题】sql连接为维恩图【英文标题】:sql joins as venn diagram 【发布时间】:2012-12-09 11:02:49 【问题描述】:我在理解 sql 中的连接时遇到了麻烦,我想到了这张我认为可能对我有帮助的图片。问题是我不完全理解它。例如,图像右上角的连接,它将整个 B 圆圈涂成红色,但仅与 A 重叠。图像使圆圈 B 看起来像是 sql 语句的主要焦点,但 sql 语句本身,从 A 开始(从 A 中选择,加入 B),给我传达了相反的印象,即 A 将是 sql 语句的焦点。
同理,下图只包含了B圈的数据,那为什么join语句中包含A呢?
问题:从右上方顺时针工作并在中心完成,有人可以提供有关每个sql图像表示的更多信息,解释
a) 为什么在每种情况下都需要连接(例如,特别是在没有从 A 或 B 获取数据的情况下,即只有 A 或 B 而不是两者都是彩色的)
b) 以及任何其他可以阐明为什么图像是 sql 的良好表示的细节
【问题讨论】:
这可能对图表Visual Explanation of Joins 更有帮助,它包括表数据,并且还有关于每种连接类型的描述。 右上图中重要的是它是一个 RIGHT JOIN,因此 TableB 的所有数据(JOIN 语句的 右侧 的表)都将被包括在内,并且仅将包含与 TableB 中的 Key 匹配的 TableA 中的数据。 维恩图的问题是,一旦你理解了连接,它一开始看起来它们说明了,但如果你真的试图解释这样的图表意味着然后您会发现它很复杂,涉及未提及的 ON 条件,涉及不在任一操作数中的行,并且对于内部连接和外部连接的解释不同。 (特别是,虽然它们看起来像维恩图,但它们不解释为维恩图),即它们不说明更不用说解释. PS 在What is the difference between “INNER JOIN” and “OUTER JOIN”? 上查看我的许多 cmets。有一个某些维恩图来说明左、右、全和内连接是如何相关的。 Say NO to Venn Diagrams When Explaining JOINs 【参考方案1】:我同意凯德关于维恩图的局限性的观点。更恰当的视觉表示可能是这样。
表格
从 A CROSS JOIN B SQL Fiddle 中选择 A.Colour、B.Colour
交叉连接(或笛卡尔积)会生成两个表中行的每个组合的结果。每个表有 4 行,因此这会在结果中产生 16 行。
从 A.Colour 的内部连接 B 中选择 A.Colour、B.Colour = B.Colour SQL Fiddle
内连接从逻辑上返回交叉连接中与连接条件匹配的所有行。在这种情况下,有五个。
从 A.Colour NOT IN ('Green','Blue') SQL Fiddle 的内部连接 B 中选择 A.Colour,B.Colour
内连接条件不一定是相等条件,也不需要引用两个(甚至其中一个)表中的列。在交叉连接返回的每一行上评估A.Colour NOT IN ('Green','Blue')
。
1=1
的内部连接条件对于交叉连接中的每一行都将评估为真,因此两者是等价的 (SQL Fiddle)。
选择 A.Colour, B.Colour 从 A.Colour 的左外连接 B 中 = B.Colour SQL Fiddle
外部联接的逻辑评估方式与内部联接相同,除了如果左表中的一行(用于左联接)根本不与右侧表中的任何行联接,则它会保留在结果中NULL
右侧列的值。
选择 A.Colour,B.Colour 从 A.Colour 的左外连接 B 中选择 B.Colour = B.Colour 其中 B.Colour 为空 SQL Fiddle
这只是将先前的结果限制为仅返回 B.Colour IS NULL
所在的行。在这种特殊情况下,这些将是保留的行,因为它们在右侧表中没有匹配,并且查询返回表B
中不匹配的单个红色行。这称为反半连接。
为IS NULL
测试选择一个不可为空或连接条件确保排除任何NULL
值的列非常重要,这样该模式才能正常工作并避免只返回除了不匹配的行之外,该列恰好具有NULL
值的行。
从 A.Colour 上的右外连接 B 中选择 A.Colour、B.Colour = B.Colour SQL Fiddle
右外连接的作用类似于左外连接,只是它们保留右表中不匹配的行,而空扩展左列。
从 A.Colour 的完整外部连接 B 中选择 A.Colour、B.Colour = B.Colour SQL Fiddle
完全外连接结合了左连接和右连接的行为,并保留左右表中不匹配的行。
【讨论】:
+1 用于apposite
视觉表示,并增加我的词汇量。
@MartinSmith 这是一个很好的解释,但我在使用 SQL 小提琴时遇到了麻烦。架构中未列出任何内容。我以前从未使用过 SQL 小提琴。
@onebree 看起来 SQL Fiddle 不会无限期地保留脚本 :-(
最好的解释,谢谢!在解释连接时应该有一些禁止维恩图的法律 - 我已经花了很多时间被他们欺骗了!
维恩图太混乱了……对于向菜鸟解释 SQL JOINS 绝对没用。他们只是将整个过程视为一个集合——如交集、并集、补集等,但他们绝对不会详细说明甚至暗示实施细节(将细节留给学生想象)。 - 这些带有颜色的图表清除了所有的混乱,非常直观。我认为所教的一切都应该如此清晰。【参考方案2】:
维恩图适用于表示集合操作,例如 UNION、INTERSECTS、EXCEPT 等。
仅当像 EXCEPT 这样的集合操作是用 LEFT JOIN WHERE rhs.KEY 为 NULL 之类的东西来模拟时,这个图是准确的。
否则会产生误导。例如,如果连接条件不是 1:1,则任何连接都可能导致行成倍增加。但是集合只允许包含不同的成员,因此不能表示为集合操作。
然后是 CROSS JOIN 或 INNER JOIN ON 1 = 1 - 这既不类似于图中所示的 INNER JOIN,也不能用维恩图真正描述所产生的集合。更不用说所有其他可能的三角连接、自连接和反连接,例如:
lhs INNER JOIN rhs ON rhs.VALUE < lhs.VALUE (triangular)
或
SELF self1
INNER JOIN SELF self2
ON self2.key <> self1.key
AND self1.type = self2.type
(self cross and anti-join 查找除自己之外的所有相似家庭成员 - self1 和 self2 是同一个集合,结果是一个真子集)
在教程的前几分钟坚持使用键连接可能没问题,但这可能会导致学习连接的内容的路径不佳。我想这就是你发现的。
维恩图通常可以以这种方式表示 JOIN 的想法需要消除。
【讨论】:
+1。我一直非常讨厌这种维恩图的使用。我觉得它直观地代表了已经很简单的连接方面,并且完全没有解释真正让人们感到困惑的连接方面。 还有一个适当的维恩图说明了内部/左/右/全连接结果之间的差异。请参阅我对这个问题的评论。【参考方案3】:对于正确的连接,是的,语法可能会令人困惑,但是的,它看起来就是这样。当您说“TableA RIGHT JOIN TableB”时,确实是在说 TableB 是您所指的主表,而 TableA 只是挂在它具有匹配记录的位置。这在查询中读起来确实很奇怪,因为 TableA 首先列出,所以您的大脑会自动为其分配更多优先级,即使 TableB 确实是查询中更重要的表。出于这个原因,您实际上很少在实际代码中看到右连接。
因此,让我们代替 A 和 B,取两件易于跟踪的事情。假设我们有两张用于人们信息的表,ShoeSize 和 IQ。你有一些人的鞋码信息,一些人的智商信息。并且在您可以加入的两个表上都有一个 PersonID。
从右上角顺时针方向(即使这从一些更复杂和人为的情况开始):
ShoeSize RIGHT JOIN IQ -> 给我所有的 IQ 信息。如果我们有这些人的任何 ShoeSize 信息,请提供这些信息。 ShoeSize RIGHT JOIN IQ WHERE ShowSize.PersonID = NULL -> 提供所有 IQ 信息,但仅适用于没有任何鞋码信息的人 ShoeSize FULL OUTER JOIN IQ WHERE ShoeSize.PersonID = NULL AND IQ.PersonID = NULL -> 只为没有 IQ 信息的人提供鞋码信息,并为没有 IQ 信息的人提供 IQ 信息鞋码信息 ShoeSize FULL OUTER JOIN IQ -> 给我一切,所有鞋码和所有 IQ 数据。如果任何 ShoeSizes 和 IQ 记录具有相同的 PersonID,请将它们包含在一行中。 ShoeSize LEFT JOIN IQ WHERE IQ.PersonID = NULL -> 提供所有鞋码信息,但仅适用于没有 IQ 信息的人 ShoeSize LEFT JOIN IQ -> 给我所有的鞋码信息。如果我们有这些人的任何智商信息,请提供这些信息。【讨论】:
【参考方案4】:当您进行连接时,您的两个表可能不会完全匹配。具体来说,A 中的某些行可能与 B 中的任何内容都不匹配,或者 A 中的重复行与 B 中的单行匹配,反之亦然。
发生这种情况时,您可以选择:
-
对于每个 A,如果有一个有效的 B,则取一个有效的 B。 (左上角)
取出完全匹配的每一对(丢弃任何缺少 A 或 B--中心的)
对于每个 B,取一个有效的 A,如果有的话(右上角)
采取一切(左下)
中心左和右在技术上是连接,但没有意义; SELECT <select_list> FROM TableA A WHERE A.Key NOT IN (SELECT B.Key FROM TableB B)
(或相反)可能会更有效地编写它们。
在直接回答您的困惑时,RIGHT JOIN
说“以下表达式是此查询的焦点”。
右下角相当奇怪,我看不出你为什么想要这样。它返回两个外部中间查询的结果,与对面表的所有列中的NULL
混合在一起。
【讨论】:
Re:“中心左侧和右侧在技术上是连接,但毫无意义;它们可能更有效地编写SELECT <select_list> FROM TableA A WHERE A.Key NOT IN (SELECT B.Key FROM TableB B)
(或相反)”:我不认为这是真的。有一些 DBMS 是等效的,还有一些 DMBS 的 LEFT JOIN
方法更有效(例如,mysql 直到 5.5 或 5.6 左右);但我不知道NOT IN
方法确实更有效的任何DBMS,尤其是在B
很大的情况下。此外,NOT IN
方法仅在加入单个字段时有效。
有趣;我原以为检查每一行会更有效,而不是加入它然后检查加入是否成功。不过,我完全可以看到多个键可以如何更快。
@ruakh - 在 SQL Server 中,对于不可为空的列 NOT IN
和 NOT EXISTS
通常会给出相同的计划,并且该计划可能比 LOJ ... NULL
更有效(有时会进行连接然后过滤掉在单独的过滤器中匹配IS NULL
的那些)。我将始终使用NOT EXISTS
而不是NOT IN
,尽管more efficient if nullable columns 和NOT IN
的语义与NULL
或永远不会是我想要的那些。
我忘记了NOT EXISTS
——那是我真正想要的,但笨拙地用NOT IN
模仿它。【参考方案5】:
我认为您的主要潜在困惑是,当(例如)仅A
以红色突出显示时,您将其理解为“查询仅返回来自A
的数据” ,但实际上它的意思是“查询只返回数据A
有记录的情况”。查询可能仍包含来自 B 的数据。(对于 B
确实没有有记录的情况,查询将替换 NULL
。)
同理,下图只包含了B圈的数据,那为什么join语句中包含A呢?
如果你的意思是——A
完全是白色的图像,B
的部分有一个红色的新月形,与A
不重叠,那么:A
的原因在查询中出现的是,A
是它如何在B
中找到需要排除的记录。 (如果A
没有出现在查询中,那么维恩图就没有A
,它只会显示B
,并且没有办法区分想要的记录和不需要的记录。)
图片看起来好像圈B是sql语句的主要焦点,但是sql语句本身以A开头(从A中选择,加入B)给我传达了相反的印象,即A会成为sql语句的焦点。
非常正确。为此,RIGHT JOIN
s 比较少见;尽管使用LEFT JOIN
的查询几乎总是可以重新排序以使用RIGHT JOIN
(反之亦然),但通常人们会使用LEFT JOIN
而不是RIGHT JOIN
编写查询。
【讨论】:
以上是关于sql连接为维恩图的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 中的 LEFT JOIN 与 LEFT OUTER JOIN