Postgresql外部加入不按预期工作

时间:2012-08-08 14:49:31

标签: postgresql outer-join

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

两个表房和可用性

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 个答案:

答案 0 :(得分:7)

问题在于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')

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

或者,您可以使用相关子查询来查找与感兴趣的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;

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