了解不同ON子句的自联接

时间:2018-04-20 15:35:42

标签: mysql sql self-join

这是我的表结构:

// mytable
+----+---------+----------+
| id | related | subject  |
+----+---------+----------+
| 1  | NULL    | subject1 |
| 2  | 1       |          |
+----+---------+----------+

有两个查询对我来说似乎相同,但在测试中有不同的结果:

SELECT a.id, IFNULL(b.subject, a.subject)
FROM mytable a
LEFT JOIN mytable b ON a.id = b.related

    +----+----------+
    | 1  | subject1 |
    | 2  |          |
    +----+----------+

SELECT a.id, IFNULL(b.subject, a.subject)
FROM mytable a
LEFT JOIN mytable b ON b.id = a.related

    +----+----------+
    | 1  | subject1 |
    | 2  | subject1 |
    +----+----------+

看,它是自我 -join。那么为什么ON a.id = b.relatedON b.id = a.related的结果不同呢?

2 个答案:

答案 0 :(得分:3)

使用SELECT *运行查询以揭示一些谜团:

您的第一个查询:

SELECT *
FROM mytable a
LEFT JOIN mytable b ON a.id = b.related;

产生以下内容:

+----+---------+----------+--------+----------+----------+
| id | related | subject  |  id1   | related1 | subject1 |
+----+---------+----------+--------+----------+----------+
|  2 | 1       | <null>   | <null> | <null>   | <null>   |
|  1 | <null>  | subject1 | 2      | 1        | <null>   |
+----+---------+----------+--------+----------+----------+

您的第二个问题:

SELECT *
FROM mytable a
LEFT JOIN mytable b ON b.id = a.related;

产生这个:

+----+---------+----------+--------+----------+----------+
| id | related | subject  |  id1   | related1 | subject1 |
+----+---------+----------+--------+----------+----------+
|  2 | 1       | <null>   | 1      | <null>   | subject1 |
|  1 | <null>  | subject1 | <null> | <null>   | <null>   |
+----+---------+----------+--------+----------+----------+

您的第一个查询是将ID 2加入相关的2。没有相关的2,由于ID 2没有主题,因此subject中没有ifnull()

您的第二个查询是将a.id 1的相关1加入ID 2。这会从b.id subject中提取1,结果会返回一个标识为2的主题。

您必须在心理上确定LEFT JOIN如何在此处工作以及它如何受您的ON子句影响。结果,您有两个非常不同的查询。

答案 1 :(得分:1)

两个查询都从a获取所有行。

两个查询都在进行外部加入b

用于寻找&#34;匹配&#34;的条件不同。来自b。

(查询似乎相同,但事实是它们有很大的不同。)

作为演示,请运行如下查询:

SELECT a.id             AS `a_id`
     , a.related        AS `a_related`
     , a.subject        AS `a_subject`
     , b.id             AS `b_id`
     , b.related        AS `b_related`
     , b.subject        AS `b_subject`
  FROM mytable a
  LEFT
  JOIN mytable b
    ON b.related = a.id

然后更改ON子句

    ON b.id = a.related

您可能还想重复这两个查询,删除LEFT关键字(使其成为内部联接而不是外部联接。)

查看外部联接的一种方法...当找到b的匹配行而不是时,会发明b的虚拟行。该虚拟行完全由NULL值组成,虚拟行与a连接,就好像它是匹配的行一样。 (这不一定是数据库引擎实际执行的操作,但以这种方式思考它可以让我们深入了解外连接返回的结果。)

仔细查看查询结果,您将能够看到查询结果不同的原因。

ab引用同一个表的事实是一个特例。如果那些是两个不同的表,我们会看到相同的结果。对于查询而言,这并不重要......这些是两个不同的来源,恰好引用同一个表。不要让ab引用同一个表格的事实引起任何混淆。