在应用左连接之前过滤表

Posted

技术标签:

【中文标题】在应用左连接之前过滤表【英文标题】:Filter Table Before Applying Left Join 【发布时间】:2013-02-11 04:36:18 【问题描述】:

我有 2 个表,我想在 2 个表连接在一起之前过滤 1 个表。

客户表:

   ╔══════════╦═══════╗
   ║ Customer ║ State ║
   ╠══════════╬═══════╣
   ║ A        ║ S     ║
   ║ B        ║ V     ║
   ║ C        ║ L     ║
   ╚══════════╩═══════╝

条目表:

   ╔══════════╦═══════╦══════════╗
   ║ Customer ║ Entry ║ Category ║
   ╠══════════╬═══════╬══════════╣
   ║ A        ║  5575 ║ D        ║
   ║ A        ║  6532 ║ C        ║
   ║ A        ║  3215 ║ D        ║
   ║ A        ║  5645 ║ M        ║
   ║ B        ║  3331 ║ A        ║
   ║ B        ║  4445 ║ D        ║
   ╚══════════╩═══════╩══════════╝

我想 Left Join,所以我从 Customer 表中获取所有记录,而不管 Entry 表中是否有相关记录。但是我想过滤条目表中的类别 D 在加入之前

期望的结果:

   ╔══════════╦═══════╦═══════╗
   ║ Customer ║ State ║ Entry ║
   ╠══════════╬═══════╬═══════╣
   ║ A        ║ S     ║  5575 ║
   ║ A        ║ S     ║  3215 ║
   ║ B        ║ V     ║  4445 ║
   ║ C        ║ L     ║  NULL ║
   ╚══════════╩═══════╩═══════╝

如果我要执行以下查询:

   SELECT Customer.Customer, Customer.State, Entry.Entry
   FROM Customer
   LEFT JOIN Entry
   ON Customer.Customer=Entry.Customer
   WHERE Entry.Category='D'

这将过滤掉最后一条记录。

所以我想要左表中的所有行并将其加入到按类别 D 过滤的条目表中。

提前感谢任何帮助!

【问题讨论】:

查看此链接 - sqlbenjamin.wordpress.com/2017/12/23/… 【参考方案1】:

或者……

SELECT c.Customer, c.State, e.Entry
FROM Customer c
LEFT JOIN Entry e
   ON c.Customer=e.Customer
WHERE e.Category IS NULL or e.Category='D'

【讨论】:

SQL JOIN 条件在 WHERE 之前执行。因此,在建议的解决方案中,整个表被连接并过滤结果 - 在处理大型表时这可能会非常昂贵。预期的过滤条件应该是其他答案中建议的 JOIN 条件的一部分 @Omley 我认为您对 SQL 的工作方式感到困惑。 SQL 是声明式,而不是过程式。查询中的单词顺序操作顺序没有影响。这取决于发动机。我们可以从一个简单的EXPLAIN 看到,mysql 在优化这个查询方面实际上比 Taryn 的答案中的查询要好得多,尽管这肯定比管理更幸运,而相反的情况很可能适用于另一个引擎。【参考方案2】:

你也可以这样做:

SELECT c.Customer, c.State, e.Entry
FROM Customer AS c
LEFT JOIN (SELECT * FROM Entry WHERE Category='D') AS e
ON c.Customer=e.Customer

SQL 小提琴here

【讨论】:

@TomJenkin 很抱歉回复晚了,我一直不在电脑旁。不过,出于好奇,我运行了这两个程序并检查了执行计划。执行计划几乎相同,但在某种程度上更好,它似乎是 Bluefeet 的版本。 太好了,这启发了我解决我的问题。【参考方案3】:

您需要将WHERE 过滤器移至JOIN 条件:

SELECT c.Customer, c.State, e.Entry
FROM Customer c
LEFT JOIN Entry e
   ON c.Customer=e.Customer
   AND e.Category='D'

见SQL Fiddle with Demo

【讨论】:

哇,你又快又高效!这就是诀窍,感谢您的帮助! @TomJenkin 谢谢,顺便说一句,您在网站上发布了一个很棒的第一个问题。很多细节等等。 谢谢 - 我想我会喜欢使用这个网站,希望有一天我能像你一样做出贡献:D @bluefeet 但两个执行计划是平等的,不是吗? 如果 where 条件指向第一个表,则在加入前对加入所依赖的表应用过滤。至少在我的一些测试中我看到了这一点。我发布了该评论以回应亚历克斯的评论。

以上是关于在应用左连接之前过滤表的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 三表链式左连接,按最后一个表过滤

交叉表左连接,Django ORM

在应用左连接之前过滤表

SQLServer 多表左连接

mysql4.0中一表关联多表左连接sql写法:

PostgreSQL同表左外连接多表