【问题标题】:MySQL: Why do select rows with NULL in LEFT JOIN, while ON x.y IS NOT NULLMySQL:为什么在 LEFT JOIN 中选择具有 NULL 的行,而 ON x.y IS NOT NULL
【发布时间】:2020-02-17 18:54:07
【问题描述】:

这里是查询:

SELECT a.name as Employee, b.name as Manager from Employee as a
LEFT JOIN Employee as b
ON a.ManagerId = b.Id AND a.ManagerId IS NOT NULL
WHERE 1

它适用于这张桌子:

+----+-------+--------+-----------+
| Id | Name  | Salary | ManagerId |
+----+-------+--------+-----------+
| 1  | Joe   | 70000  | 3         |
| 2  | Henry | 80000  | 4         |
| 3  | Sam   | 60000  | NULL      |
| 4  | Max   | 90000  | NULL      |
+----+-------+--------+-----------+

作为 Idea,此查询应显示所有雇主。一组具有 a.ManagerId = b.Id 的行。

一切正常,除了行

Sam, NULL Max, NULL

为什么这些行返回。如果我在ON 子句中设置a.ManagerId is NOT NULL。

【问题讨论】:

  • NULL 是一头奇怪的野兽。这就是为什么。
  • 我想你可以参考这里更清楚地了解加入条件的“on”和“where”阶段之间的区别。 stackoverflow.com/questions/354070/…
  • 不是因为 NULL,而是因为“ON”是如何工作的。 'ON' 通过某些规则给出与 B 行连接的所有 A 行。无论如何,所有 A 行都将显示在答案中。在过滤 A 行旁边,需要使用“WERE”。在这种情况下,为 ON 添加一条规则,它没有为 ManagerID 为 NULL 的情况附加 B 行,但它不会拒绝这些行。
  • 无论你在 ON 子句中写什么,你都会得到来自a 的所有行。这就是 LEFT JOIN 的工作原理。
  • @PaulSpiegel 说得更正确,至少会使用 A 形式的所有行。万一ON FALSE,万一ON TRUE将是A行B次。

标签: mysql null left-join


【解决方案1】:

写查询时

SELECT x from A
LEFT JOIN B
ON  A.b_id = b.id

选择所有表 A 并连接到 B。但使用所有 A。

在示例的情况下,A 和 B 表是相同的,但尽管如此。我们有 A 表的完整列表,其中每一行附有或不附有 B 表的一行。

所以要减少A表的行数需要用WERE CLAUSE控制它

正确的查询是

SELECT a.name as Employee, b.name as Manager from Employee as a
LEFT JOIN Employee as b
ON a.ManagerId = b.Id  
WHERE a.ManagerId IS NOT NULL
  1. ON 子句用于定义规则将哪些行附加到 A 表
  2. WERE 子句过滤步骤 1 中的行。换句话说,在此示例中,从 A 表中“剪切”一些行。

当我使用ON FAlSE时:它只选择A中的所有行,而不与B行连接。

SELECT a.name as Employee from Employee as a
LEFT JOIN Employee as b
ON false
WHERE 1
  • 乔
  • 亨利
  • 山姆
  • 最大

当我使用ON TRUE 时,它使用所有A 行B 次。

SELECT a.name as Employee from Employee as a
LEFT JOIN Employee as b
ON true
WHERE 1
{"headers": ["Employee"], "values": 
[
["Joe"], ["Henry"], ["Sam"], ["Max"], 
["Joe"], ["Henry"], ["Sam"], ["Max"],
["Joe"], ["Henry"], ["Sam"], ["Max"], 
["Joe"], ["Henry"], ["Sam"], ["Max"]]}

【讨论】:

  • 您能否澄清一下,LEFT JOIN ON 没有 INNER 或 OUTER 前缀 - 是 INNTER 或 OUTER 默认?
  • 没有 INNER LEFT/RIGHT/FULL JOIN ON--这些是 3 个 OUTER JOIN。 LEFT/RIGHT/FULL JOIN ON 是 LEFT/RIGHT/FULL OUTER JOIN ON。没有 INNER 或 LEFT 或 RIGHT 或 FULL 的 JOIN ON 是 INNER JOIN ON。逗号表示 CROSS JOIN,但优先级低于关键字 JOIN。此外,INNER/LEFT/RIGHT/FULL JOIN ON 1=1 都是 CROSS JOIN。 (MySQL 允许 (INNER) JOIN without ON 表示 CROSS JOIN;但这是非标准的。MySQL 没有 FULL (OUTER) JOIN ON)。阅读权威描述——教科书或manual。
  • 如果我已经发布了以下内容,请原谅我:这篇帖子的意义何在?它陈述了很多事情,但它们与这个问题有什么关系呢?如果此文本只是附加问题,请将其编辑到问题帖子中。此外,其中大部分都非常不清楚。此外,它试图说明一些关于一些操作符调用的事情,但它肯定没有清楚地描述这些操作符是如何工作的。
  • 我在之前的评论中犯了一个错误,当我说你把内连接变成外连接时。你没有。你有一个 LEFT JOIN b ON c WHERE a.ManagerId 不为空。 WHERE 不需要任何 b 列不为空。 (WHERE 从外连接中删除 a.ManagerId 为空的行。对于该 c,在表 a 中每行的输出中将有一行,ManagerId 为空。)
【解决方案2】:
 a.Manager IS NOT NULL 

引用表Employee a的别名 而是将 NULL 值引用到别名表 Employee b

表的别名用作新分离表的相关行

在 sql 中,当您需要原始表中的值用于不同用途和连接时,这是典型的

您应该将表格行视为数据集,而别名是相同数据的分离集

【讨论】:

    猜你喜欢
    • 2011-01-15
    • 2012-07-15
    • 2020-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-21
    相关资源
    最近更新 更多