理解这个 SQL LEFT JOIN (with IS NULL) 例子

Understanding this SQL LEFT JOIN (with IS NULL) example

在数据库中,有一个 table 称为类别:

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

创建它是为了制作相邻列表模型树。这是目前 table 中的内容:

在这个例子中(你可以在底部找到来源link),下面的sql代码用于获取[=47=中的"leaf"个元素],"leaf" 元素是 table 中没有任何其他行的行,在 "parent" 列中使用它们的 "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代码的结果给出了这个结果:

例如,table 中没有父列中值为 3 的行,因此 TUBE(category_id == 3)是一个 "leaf" 元素.

问题: 为什么 sql 代码在逻辑上给出了这个结果?我很高兴它确实如此,因为它正是我所需要的,但我无法理解它背后的原因。


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

每当您看到此模式时:

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

思考:“在 TableA 中找到 TableB 中不存在的行。

您的查询意味着 "find categories that have no child"。如果您删除 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 table 开始,将其别名为 t1t2。从现在开始我将引用别名。
  2. 对于 t1 中的每一行,查找 t2 中将 t1 行标识为其父行的所有记录
  3. 如果 t1 行没有子行,t2.category_id 将为空
  4. 我们只想筛选 t1 没有子项的行

我认为如果您重命名您的 table 别名会更容易看到发生了什么:

    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]