Postsgresql外部加入不按预期工作

Rob*_*wie 3 postgresql outer-join

一个看似简单的查询,我无法工作......

两个桌子的房间和可用性

Room         [id, title, beds]
Availability [room_id, date, bed_delta]
Run Code Online (Sandbox Code Playgroud)

客房配有固定的最多床位数.可用性描述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;
Run Code Online (Sandbox Code Playgroud)

此查询仅在匹配的行中返回availability.我期望的是id为== 2的房间的单行.

j_r*_*ker 7

问题是你的WHERE条款的这一部分:

WHERE date = '2012-01-01 09:00:00+01:00'
Run Code Online (Sandbox Code Playgroud)

外连接仅"允许" 连接条件(此处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')
Run Code Online (Sandbox Code Playgroud)

(是的,令人惊讶的是,你可以在那里坚持任意条件,正如你现在发现的那样,(对于外连接)这可能是必要的!)

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

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;
Run Code Online (Sandbox Code Playgroud)

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

  • @RobCowie 如果这个答案如你所愿是正确的意味着请接受这个答案,这也可能对其他人有帮助。 (2认同)