使用 WHERE 子句加入多个表,包括没有公共 ID 的行

Posted

技术标签:

【中文标题】使用 WHERE 子句加入多个表,包括没有公共 ID 的行【英文标题】:Multiple tables JOIN with WHERE clause including rows that haven't common id 【发布时间】:2020-11-15 12:39:06 【问题描述】:

我想这个话题已经在这里讨论过了。但是我找不到对我的问题有用的东西,因此欢迎提供链接。

一共有三张桌子。表test2 有两个表test1test3 的外键。

    test1                          test2                               test3
+----+------+           +----+-------+-------+----+             +----+------------+
| id | name |           | id | t1_id | t3_id | v2 |             | id |   co_date  |
+----+------+           +----+-------+-------+----+             +----+------------+
|  1 |   A  |           | 1  |   3   |   1   | 15 |             |  1 | 2018-12-02 |
|  2 |   B  |           | 2  |   4   |   1   | 20 |             |  2 | 2019-02-03 |
|  3 |   C  |           | 3  |   9   |   2   | 35 |             |  3 | 2019-03-04 |
|  4 |   D  |           | 4  |   5   |   3   | 12 |             |  4 | 2019-04-05 |
|  5 |   E  |           | 5  |   6   |   3   | 12 |             |  5 | 2019-09-01 |
|  6 |   F  |           | 6  |   9   |   4   | 20 |             |  6 | 2019-10-02 |
|  7 |   G  |           | 7  |   6   |   5   | 10 |             |  7 | 2019-11-03 |
|  8 |   H  |           | 8  |   7   |   5   | 10 |             |  8 | 2019-12-04 |
|  9 |   I  |           | ....................... |             |  9 | 2020-02-05 |
| 10 |   J  |           | 20 |   4   |  10   | 30 |             | 10 | 2020-03-06 |
+----+------+           +----+-------+-------+----+             +----+------------+

我想在特定时期内按名称对test2 中的所有 v2 值求和。问题是在那个时期没有出现一些名字。并且它们被排除在查询结果之外。

我尝试使用左手连接,但它不起作用。

SELECT t1.name, SUM(v2) FROM test1 as t1
LEFT OUTER JOIN test2 as t2 
  ON t1.id = t2.t1_id
LEFT OUTER JOIN test3 as t3 
  ON t2.t3_id = t3.id
WHERE co_date BETWEEN '2019-01-01' AND '2019-12-31'
GROUP BY name
ORDER BY name

以下结果不包括 'A''D' 的名称。

+------+---------+
| name | SUM(v2) |
+------+---------+
|   E  |    26   |
|   F  |    37   |
|   G  |    35   |
|   H  |    10   |
|   I  |    90   |
|   J  |    20   |
+------+---------+

但我希望他们应该与NULL 在其他领域。 LEFT JOIN 的工作方式不就是这样:左表中的所有行以及与其他表的交集吗?

另外,我尝试过笛卡尔积,但我不知道如何正确分组。

Here's the demo。 对于我应该如何思考的任何建议,我将不胜感激。

【问题讨论】:

【参考方案1】:

您需要在ON 子句中包含日期过滤器:

SELECT t1.name, SUM(v2)
FROM test1 t1 LEFT JOIN
     test2 t2 
     ON t1.id = t2.t1_id LEFT JOIN
     test3 t3 
     ON t2.t3_id = t3.id AND
        t3.co_date BETWEEN '2019-01-01' AND '2019-12-31'
GROUP BY t1.name
ORDER BY name;

WHERE 子句将外连接变为内连接——这就是丢失行的原因。这样做是因为 NULL 未能在 WHERE 子句中过滤“外部连接”结果的比较。

【讨论】:

为什么没有在各种 JOIN 类型描述中说明它?.. 谢谢你,Gordon。 @Gennadiy:他们没有明确这样做,但他们提到外部连接的列是空的,所以WHERE t3.co_date BETWEEN DATE '2019-01-01' AND DATE '2019-12-31' 必须忽略这些行。

以上是关于使用 WHERE 子句加入多个表,包括没有公共 ID 的行的主要内容,如果未能解决你的问题,请参考以下文章

搜索功能 - 加入具有多行和 where 子句的查找表

C# LINQ 与两个不同数据集上的条件 where 子句连接

Django 使用 ORM 和条件 Where 子句连接表

使用一个 WHERE 子句更新多个表

使用多个 WHERE 有效地连接两个表

SQL:在 Where 子句之后加入