右表中空结果的内连接

Posted

技术标签:

【中文标题】右表中空结果的内连接【英文标题】:inner join with empty result from right table 【发布时间】:2013-08-08 21:06:31 【问题描述】:

我有2张桌子,餐厅和订单,每个餐厅可以有很多订单

restaurants table
id
name


orders table
id
restaurant_id
date

我需要找到在某个日期范围内没有订单的餐厅。在订单表中,我将订单日期保存为 - 每行代表一天。所以,我需要进行内部连接,但订单表没有结果。比如说,我需要找到在2013-08-09 to 2013-08-11 日期范围内免费的餐厅。我怎样才能做到这一点?如何根据日期范围查询订单表中没有匹配项的餐厅?

实际上,我可以将状态为 not_ordered 的订单表中的所有日期保存起来,并使用not_ordered = true 条件进行内部连接,但在这种情况下,我必须使用日期填充所有表,这不是对我来说是件好事。

谢谢

【问题讨论】:

看看here also,类似的问题,但joins没有重音 【参考方案1】:
select r.*
from restaurant r
left join orders o on r.id = o.restaurant_id and o.date between '...' and '...'
where o.id is null;

或者您可以使用not exists 来完成,如其他答案所示。

【讨论】:

+1。这是经典的“反连接”模式:一个 LEFT JOIN 来查找匹配的行(所有餐厅以及匹配的订单),然后是一个 WHERE 子句来消除在订单中具有匹配行的餐厅。这通常比使用 NOT INNOT EXISTS 谓词的等效查询。【参考方案2】:

您不想为此使用内部联接。您可以使用外连接,或使用NOT EXISTS 和子查询。

这是后一种方法的一个示例:

select r.id,r.name 
from restaurants r 
where not exists (
  select NULL
  from orders o 
  where o.restaurant_id = r.id 
  and o.date >= '2013-08-09'
  and o.date <= '2013-08-11'
);

【讨论】:

+1。相关子查询引用了外部查询中的表达式。这就是它的完成方式,尽管我们通常(并非总是)通过反连接获得更好的性能。 我自己更经常使用反连接,但我认为了解这两种方法很有用。 我同意了解这两种方法很有用,这就是为什么我赞成您的回答。有时NOT EXISTS 谓词是更合适的方法。【参考方案3】:

我不是很了解mysql,但这应该可以作为通用SQL:

SELECT * 
FROM restaurants 
WHERE NOT EXISTS(SELECT 1 
                 FROM order 
                 WHERE restaurant_id=id AND 
                       date BETWEEN '2013-08-09' AND '2013-08-11')

【讨论】:

子查询中的id 是对restaurant 表或order 表中的id 列的引用吗?最佳实践要求列引用必须使用表名或最好使用表别名来限定。

以上是关于右表中空结果的内连接的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 的内连接、左连接、右连接有啥区别?

左外连接右外连接内连接全连接的概念

mysql 连接

内连接与左外链接的区别

SQL——左连接(Left join)右连接(Right join)内连接(Inner join)

左外连接和右外连接的区别