左连接至少有一行满足右侧MySQL条件

9
我有两个表,餐厅和订单,订单表中有restaurant_idstatusdate字段,在订单表中每天都有一行记录。 我需要筛选出餐厅,并仅显示在某个日期范围内至少有一个预订的餐厅,但必须在日历上显示,看起来像是带有信息的餐厅列表。 类似于这样:

enter image description here

因此,如果该日期范围内满足至少有一个保留状态的日期条件,则应获取该餐厅该日期范围内所有订单。 我无法进行常规的内部联接。
SELECT r.`id`, r.`name`, o.`date`, o.`status`
FROM restaurants r
INNER JOIN orders o ON r.id = o.restaurant_id AND o.date BETWEEN '2013-08-10' AND '2013-08-31'
AND status = 'reserved' 

因为在这种情况下,例如,我将无法获得8月31日餐厅2的订单信息,因为尽管它在10-31的日期范围内,但其状态为“关闭”。 因此,我考虑进行左连接,如下所示:

SELECT r.`id`, r.`name`, o.`date`, o.`status`,  o.`id` order_id
FROM restaurants r
LEFT JOIN orders o ON r.id = o.restaurant_id AND
o.date BETWEEN '2013-08-10' AND '2013-08-31' 
WHERE o.`id` IS NOT NULL 

但是我还需要添加一个条件,以确保至少有一行订单状态为“reserved”,我尝试添加像COUNT(o.status = 1) > 0这样的where子句,但它会报错。

谢谢。


1
使用子查询来获取至少有一条记录状态为“已预订”的餐厅,然后可以使用内连接。 - Dan Bracuk
@DanBracuk,您能详细解释一下吗?谢谢。 - dav
1个回答

6

我认为实现这一目标的最好方法(假设“N/A”和“reserved”等内容存储在订单表中),是首先连接所有订单,然后使用第二个连接将其限制为仅具有该期间内预订的餐厅:

SELECT  r.`id`, r.`name`, o.`date`, o.`status`,  o.`id` order_id
FROM    restaurants r
        INNER JOIN orders o 
            ON r.id = o.restaurant_id
            AND o.date BETWEEN '2013-08-10' AND '2013-08-31' 
        INNER JOIN
        (   SELECT  DISTINCT o2.Restaurant_ID
            FROM    orders o2
            WHERE   o2.date BETWEEN '2013-08-10' AND '2013-08-31' 
            AND     o2.Status = 'Reserved'
        ) o2
            ON r.id = o2.restaurant_id;

Example on SQL Fiddle


你无法想象我有多感激你:)。非常感谢。让我问一件事——如果我有数十万家餐厅,这会很昂贵吗?我需要优化哪些指标? - dav
是的,这可能是最可扩展的解决方案。我不知道您在表上可能使用哪些其他查询,但对于此问题,我会在orders上建立3个索引,分别是restaurant_idstatusdate,或者根据您的分布情况,只建立2个索引,其中一个索引包含两个列,具体情况难以确定。例如,如果每个餐厅每天的订单都是唯一的,则我会在这两个列上添加唯一索引,并在状态上添加单个非聚集索引。 - GarethD
非常感谢你的帮助。我还想问一件事。我试图使用相同的查询但是用左连接(反向连接)来获取免费餐厅,但我无法弄清楚怎么做,如果你能帮我解决这个问题,那就太好了 - 我为此发布了一个新问题http://stackoverflow.com/questions/18362311/left-join-with-empty-rows-from-right-table-mysql。谢谢。 - dav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,