在JSONB数组中按唯一值分组

时间:2016-07-27 10:59:18

标签: postgresql jsonb

考虑以下表格结构:

CREATE TABLE residences (id int, price int, categories jsonb);

INSERT INTO residences VALUES
  (1, 3, '["monkeys", "hamsters", "foxes"]'),
  (2, 5, '["monkeys", "hamsters", "foxes", "foxes"]'),
  (3, 7, '[]'),
  (4, 11, '["turtles"]');

SELECT * FROM residences;

 id | price |                categories
----+-------+-------------------------------------------
  1 |     3 | ["monkeys", "hamsters", "foxes"]
  2 |     5 | ["monkeys", "hamsters", "foxes", "foxes"]
  3 |     7 | []
  4 |    11 | ["turtles"]

现在我想知道每个类别有多少住宅,以及它们的价格总和。我发现的唯一方法是使用子查询:

SELECT category, SUM(price), COUNT(*) AS residences_no
FROM
  residences a,
  (
    SELECT DISTINCT(jsonb_array_elements(categories)) AS category
    FROM residences
  ) b
WHERE a.categories @> category
GROUP BY category
ORDER BY category;

  category  | sum | residences_no
------------+-----+---------------
 "foxes"    |   8 |             2
 "hamsters" |   8 |             2
 "monkeys"  |   8 |             2
 "turtles"  |  11 |             1

使用不带子查询的jsonb_array_elements会因为第二行中的重复条目而为狐狸返回三个住所。此外,住宅的价格将被夸大5。

有没有办法在不使用子查询的情况下执行此操作,或者有更好的方法来完成此结果?

修改

最初我没有提到价格栏。

1 个答案:

答案 0 :(得分:2)

select category, count(distinct (id, category))
from residences, jsonb_array_elements(categories) category
group by category
order by category;

  category  | count 
------------+-------
 "foxes"    |     2
 "hamsters" |     2
 "monkeys"  |     2
 "turtles"  |     1
(4 rows)

您必须使用派生表来聚合另一列(所有价格均为10):

select category, count(*), sum(price) total
from (
    select distinct id, category, price
    from residences, jsonb_array_elements(categories) category
) s
group by category
order by category;

  category  | count | total 
------------+-------+-------
 "foxes"    |     2 |    20
 "hamsters" |     2 |    20
 "monkeys"  |     2 |    20
 "turtles"  |     1 |    10
(4 rows)