使用连接查询 JSONB 字段

Querying JSONB fields with joins

我有一个包含两个 table 的数据库。一个包含事件,另一个包含这些事件的参与者。这些事件有一个 jsonb 字段,其中包含一个具有 "duration" 属性

的对象数组

事件

id name occurrences
1 "The Great Beyond" [{"duration": 100}, {"duration": 200}, {"duration": 300}]
2 "The Final Countdown" [{"duration": 50}]
3 "The Next Plain" null

与会者

id name event_id
1 "Bob" 1
2 "Susan" 2
3 "Terry" 3

我想 运行 一个查询来提取有关这些事件的数据并展示事件的名称、有多少人参加以及每个事件的当前“持续时间”是多少(通过总结occurrences 列中的所有 duration 值。

我使用的当前查询导致与会者的 COUNT 值不正确。我怀疑这与我构建 JOIN 的方式有关,因此正在创建额外的行。

SELECT
  events.id AS "ID",
  events.name AS "Name",
  SUM(coalesce(occurrences_arry->'duration', '0'):int) as "Duration",
  COUNT(attendees.*) as "Attendees"
FROM
  events
    INNER JOIN attendees on attendees.event_id = events.id
    LEFT JOIN jsonb_array_elements(events.occurrences) as occurrences_arry on true
GROUP BY events.id

我返回的结果对“与会者”的计数太高(最后一条记录应该有 1 名与会者,但说是 3 人)。我很确定它与我正在使用的 INNER JOIN LEFT JOIN 组合有关,因此我可以利用 jsonb_array_elements。每次添加新事件时,与会者人数都会增加 ‍

ID Name Duration Attendees
2 "The Final Countdown" 50 1
3 "The Next Plain" 0 1
1 "The Great Beyond" 600 3

我如何才能最好地对我的与会者 table 执行 INNER JOIN 并总结每个活动的所有 duration

您可以在子查询中计算持续时间。您已经拥有大部分需要的代码,只需移动它,例如:

SELECT
  events.id AS "ID",
  events.name AS "Name",
  (SELECT coalesce(SUM((occurrences_arry->>'duration')::int), 0)
   FROM jsonb_array_elements(events.occurrences) as occurrences_arry) as "Duration",
  COUNT(attendees.*) as "Attendees"
FROM
  events
    INNER JOIN attendees on attendees.event_id = events.id
GROUP BY events.id

A SUM returns null,如果没有行,因此在这种情况下我使用 coalesce 默认为 0。