Left Join / IS NULL 如何消除一个 table 而另一个 table 中没有的记录?

How does Left Join / IS NULL eliminate records which are there in one table and not in the other?

我很难理解为什么 LEFT JOIN / IS NULL 会删除一个 table 而另一个 table 中没有的记录。 这是一个例子

SELECT  l.id, l.value
FROM    t_left l
LEFT JOIN t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

为什么要r.value = NULL 删除记录?我不理解 。我知道我遗漏了一些非常基本的东西,但目前我什至无法弄清楚那个基本的东西。如果有人向我详细解释,我将不胜感激。

我想要一个非常基本的解释。

 SELECT * FROM a LEFT JOIN b ON a.v = b.v ... WHERE b.id IS NULL

这是超级简单的逻辑:

  • select 来自 table "a"
  • join table "b"(如果存在匹配行 - ON a.v=b.v 否则使用 NULL 作为值)
  • WHERE 条件:如果缺少某些内容(b.id IS NULL)= OK。

左边 returns 从左边开始的所有行 table

ON r.value = l.value
如果 l.value 没有 r.value 那么 r 是空的
r.value 为空将为真

在您的示例中,结果将是来自 t_left 的每条记录,以及来自 t_right 的每条匹配记录,它们都具有相同的 value。如果没有匹配项,则会给出 NULL 值而不是 t_right 中的值。 where r.value is null 通过检测那些 null 值简单地消除匹配的行。

本质上是说“给我 t_left 中不匹配 t_right

中的行的行

a right join 执行与 left join 相反的顺序。

这是基于INNER JOINLEFT JOIN的区别。当您使用 INNER JOIN 时,结果仅包含两个 table 之间匹配的行(基于 ON 条件)。

但是当您使用 LEFT JOIN 时,您还会在结果中获得第一个 table 中 没有 的所有行的行第二场比赛 table。在这些情况下,第二个 table 的所有结果列都用 NULL 作为占位符填充。

然后 WHERE r.value IS NULL 测试匹配这些行。所以最终结果只包含没有匹配的行。

LEFT JOIN 获取左侧的值并尝试将左侧的 table 与 ON 指定的列相匹配,如果找不到匹配项,则解释右侧的 table的列为 NULL。因此只有那些在右边找不到匹配项的 table 才会被 IS NULL operator

选择

首先,左联接声明将包括来自左侧 table 的所有记录,并且仅包括来自右侧的匹配记录。

假设你的抽屉里有 redbluegreen 袜子,而你的朋友只有 redyellowblue,从你的抽屉到你的朋友的左连接会 return 你抽屉里的所有袜子(redbluegreen)并且只有匹配的袜子来自您的朋友(redblue)。

现在 IS NULL 部分表示您想查看抽屉中的所有袜子,而您的朋友抽屉中没有配对配对,因此在您所有的袜子中,唯一缺少一双的是 green 袜子.

这句话:

SELECT  l.id, l.value
FROM    t_left l
LEFT JOIN t_right r
ON      r.value = l.value

会将 t_left table 中的所有元素连接到 t_right table 中的所有元素。正如您现在可能会看到的那样,在 INNER JOIN 中只会显示同时匹配 table 的行,因此 t_left 的行数 可能比所有行都少可能的行。在 LEFT JOIN 中,您拥有来自 t_left table 的所有行以及来自 t_right 的匹配行(如果它们可以连接)。那么,如果 t_left 中的行不匹配任何 t_right 行,会发生什么情况? t_right table 中本应包含数据的所有字段都将填充 NULL 值。所以,如果你只从右边 table select NULL 值,你会发现 t_left table 右边没有匹配的所有值一、XD

这可以用以下解释

mysql> select * from table1 ;
+------+------+
| id   | val  |
+------+------+
|    1 |   10 |
|    2 |   30 |
|    3 |   40 |
+------+------+
3 rows in set (0.00 sec)

mysql> select * from table2 ;
+------+------+
| id   | t1id |
+------+------+
|    1 |    1 |
|    2 |    2 |
+------+------+
2 rows in set (0.00 sec)

这里table1.id <-> table2.t1id

现在,当我们使用连接键执行 left join 时,如果左侧 table 是 table1 那么它将从 table1 获取所有数据,并且table2 上的非匹配记录将被设置为 null

mysql> select t1.* , t2.t1id from table1 t1 
left join table2 t2 on t2.t1id = t1.id ;
+------+------+------+
| id   | val  | t1id |
+------+------+------+
|    1 |   10 |    1 |
|    2 |   30 |    2 |
|    3 |   40 | NULL |
+------+------+------+

3 rows in set (0.00 sec)

看到 table1.id = 3 在 table2 中没有值,所以它设置为 null 当您应用 where 条件时,它将进行进一步过滤

mysql> select t1.* , t2.t1id from table1 t1 
left join table2 t2 on t2.t1id = t1.id where t2.t1id is null;
+------+------+------+
| id   | val  | t1id |
+------+------+------+
|    3 |   40 | NULL |
+------+------+------+
1 row in set (0.00 sec)

Left join 给出左起 table 的所有记录。如果左侧 table 中存在的任何键在右侧 table 中丢失,则所有右侧 table 列将为空,但所有左侧 table 值都将存在。

这是inner join和left/right join的基本区别

因此,当您执行“r.value = null”时,您会从左侧获取那些在右侧 table.

中没有匹配键的记录

HTH.

很简单左加入基金会..... 以下查询从左侧 table 获取所有记录并从右侧 table 获取所有匹配记录,如果不匹配,它将 return NUll 值。最后,您使用 where 条件过滤数据,其中 return 值 在左侧 table 但不在右侧 table

 SELECT  l.id, l.value
    FROM    t_left l
    LEFT JOIN t_right r
    ON      r.value = l.value
    WHERE   r.value IS NULL

假设 r-table 是员工,r_table 是计算机。有些员工没有电脑。部分计算机尚未分配给任何人。

  1. 内部联接:

    SELECT  l.*, r.*
    FROM    employees l
    JOIN computers r
    ON      r.id = l.comp_id
    

    为您提供拥有计算机的所有员工的列表,以及为每个人分配的计算机信息。没有电脑的员工将不会出现在此列表中。

  2. 左连接:

    SELECT  l.*, r.*
    FROM    employees l
    LEFT JOIN computers r
    ON      r.id = l.comp_id
    

    为您提供所有员工的列表。有电脑的员工会显示电脑信息。没有计算机的员工将显示 NULL 而不是计算机信息。

  3. 终于

    SELECT  l.*, r.*
    FROM    employees l
    LEFT JOIN computers r
    ON      r.id = l.comp_id
    WHERE   r.id IS NULL
    

    带 WHERE 子句的左连接将从与左连接 (2) 相同的列表开始,但它只会保留那些没有相应信息的员工电脑table,即没有电脑的员工

    在这种情况下,select r table 中的任何内容都将只是空值,因此您可以将这些字段排除在外,而 select 仅来自 select l table:

    SELECT  l.*
    FROM ...
    

尝试这个 select 序列并观察输出。每一步都建立在前一步的基础上。

请让我知道这个解释是否可以理解,或者你希望我详细说明一些。

编辑添加: 下面是创建上面使用的两个 table 的示例代码:

CREATE TABLE employees
(  id INT NOT NULL PRIMARY KEY,
   name VARCHAR(20),
   comp_id INT);

INSERT INTO employees (id, name, comp_id) VALUES (1, 'Becky', 1);
INSERT INTO employees (id, name, comp_id) VALUES (2, 'Anne', 7);
INSERT INTO employees (id, name, comp_id) VALUES (3, 'John', 3);
INSERT INTO employees (id, name) VALUES (4, 'Bob');

CREATE TABLE computers
(  id INT NOT NULL PRIMARY KEY,
   os VARCHAR(20) );

INSERT INTO computers (id, os) VALUES (1,'Windows 7');
INSERT INTO computers (id, os) VALUES (2,'Windows XP');
INSERT INTO computers (id, os) VALUES (3,'Unix');
INSERT INTO computers (id, os) VALUES (4,'Windows 7');

有4名员工。贝基和约翰有电脑。安妮和鲍勃没有电脑。 (安妮有一个 comp_id 7,它不对应于计算机中的任何行 table - 所以,她实际上没有计算机。)