Postgresql 外部联接未按预期工作

Posted

技术标签:

【中文标题】Postgresql 外部联接未按预期工作【英文标题】:Postsgresql Outer Join not working as intended 【发布时间】:2012-08-05 17:16:15 【问题描述】:

一个看似简单的查询,我做不来......

两张桌子的房间和空房

Room         [id, title, beds]
Availability [room_id, date, bed_delta]

一个房间有一个固定的最大可用床位数。可用性描述了Room.beds 被修改(向上或向下)的时间段。

我正在尝试构建一个查询,对于给定的房间和给定的开始日期和持续时间,将汇总可用床位。

例如:

1 号房间通常有 2 张床 1 小时,占用 1 张床 预期结果为 1

如果添加了与此日期时间范围重叠的另一个可用时间段,并将床位进一步减少 1,则预期结果为 0。

感觉是一个比较简单的查询:

LEFT OUTER JOIN 房间到 room_id 的可用性 按日期限制 选择 Room.beds - sum(Availability.bed_delta)

SELECT r.beds - coalesce(sum(a.bed_delta), 0) as beds_free
FROM room r
LEFT OUTER JOIN availability a ON (r.id = a.room_id)
WHERE date = '2012-01-01 09:00:00+01:00'
AND r.id = 2
GROUP BY r.id;

此查询仅在availability 中存在匹配行时返回。我期望的是 id == 2 的房间只有一行。

【问题讨论】:

【参考方案1】:

问题在于您的WHERE 子句的这一部分:

WHERE date = '2012-01-01 09:00:00+01:00'

外连接仅“允许”连接条件(此处为r.id = a.room_id)失败的行; WHERE 子句中对右侧表施加的其他约束仍然可以从结果中排除整行。是的,这很棘手。

解决方案:将date约束移到连接条件中:

LEFT OUTER JOIN availability a ON (r.id = a.room_id AND date = '2012-01-01 09:00:00+01:00')

(是的,令人惊讶的是,您可以在其中添加任意条件,并且正如您现在发现的那样,(对于外部连接)这可能是必要的!)

或者,您可以使用相关子查询来查找与感兴趣的Room 匹配的所有Availability 记录的总和:

SELECT r.beds - coalesce((
    SELECT sum(a.bed_delta)
    FROM availability a
    WHERE a.room_id = r.id
    AND date = '2012-01-01 09:00:00+01:00'
), 0) as beds_free
FROM room r
WHERE r.id = 2;

我发现子查询比 GROUPed 外连接更容易理解,但是 YMMV。

【讨论】:

干杯,非常有用。恐怕我被多年的 mysql 使用弄脏了。对相关子查询的性能影响有何评论? 不客气。据我所知,没有关于性能的硬性规定。查询计划器将考虑许多不同的可能计划,并且知道将查询转换为其他等效查询的多种方法,因此它很可能为两者生成相同的查询计划。使用EXPLAINEXPLAIN ANALYZE 看看它认为什么是最好的。 @RobCowie 如果此答案如您预期的那样正确,则表示请接受该答案,这也可能对其他人有帮助。 解释器允许你否定 OUTER JOIN 的事实太愚蠢了。它应该引发警告或错误。这困扰了我好几年。

以上是关于Postgresql 外部联接未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql 可序列化事务未按预期工作

针对特定用户的 PostgreSQL RLS 策略未按预期工作并适用于所有用户

Restangular POST 请求未按预期工作

从 .Net 应用程序到 AWS API Gateway 的 HTTP POST 请求未按预期工作

Azure NSG 未按预期工作

Javascript:Jquery 发布请求未按预期工作