理解这个SQL LEFT JOIN(带有IS NULL)的例子

时间:2016-04-21 03:21:07

标签: mysql sql tree adjacency-list

在数据库中,有一个名为category的表:

CREATE TABLE category(
        category_id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(20) NOT NULL,
        parent INT DEFAULT NULL
);

它是为了制作相邻列表模型树而创建的。以下是目前表格中的内容:

enter image description here

在这个例子中(你可以在底部找到源链接),下面的sql代码用于获取表中的“leaf”元素,“leaf”元素是表中没有的行任何其他行在“父”列中使用其“category_id”。运行以下代码:

SELECT t1.name FROM
category AS t1 LEFT JOIN category as t2
ON t1.category_id = t2.parent
WHERE t2.category_id IS NULL;

以前的SQL代码的结果给出了这个结果:

enter image description here

例如,表中没有行在父列中具有值3,因此TUBE(with category_id == 3)是“leaf”元素。

问题:为什么这个sql代码在逻辑上给出了这个结果?我很高兴它确实存在,因为它是我所需要的,但我不能完全围绕它背后的推理。

示例来源:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

2 个答案:

答案 0 :(得分:2)

每当你看到这种模式时:

SELECT    ...
FROM      TableA
LEFT JOIN TableB ON TableA.column = TableB.column
WHERE     TableB.id is null

思考:"在TableA中查找TableB中不存在的行。

您的查询意味着找到没有孩子的类别"。如果删除WHERE子句并在查询中添加更多列,则更容易理解:

SELECT      t1.category_id,
            t1.name,
            t2.name  AS ChildName
FROM        category AS t1
LEFT JOIN   category as t2 ON t1.category_id = t2.parent

以下是您的查询中发生的情况:

  1. category表开始,将其别名为t1t2。我将从现在开始引用别名。
  2. 对于t1中的每一行,查找t2中标识t1行为其父
  3. 的所有记录
  4. 如果t1行没有孩子,t2.category_id将为空
  5. 我们只想过滤没有孩子的t1

答案 1 :(得分:0)

我认为如果重命名表别名,将会更容易看到发生了什么:

    SELECT tparent.name 
      FROM category AS tparent 
      LEFT JOIN category as tchild
        ON tparent.category_id = tchild.parent
     WHERE tchild.category_id IS NULL;

现在可能更容易看到你要求的是没有孩子的所有父类别名称的列表[tchild.category_id IS NULL]