我有一个带有id的实体表,以及一个类别(几个不同的值允许使用NULL)来自3个不同年份(类别可以从1年到另一年不同),采用“宽”表格格式:
| ID | CATEG_Y1 | CATEG_Y2 | CATEG_Y3 |
+-----+----------+----------+----------+
| 1 | NULL | B | C |
| 2 | A | A | C |
| 3 | B | A | NULL |
| 4 | A | C | B |
| ... | ... | ... | ... |
我想简单地按类别计算实体数量,按类别分组,单独计算年份:
+-------+----+----+----+
| CATEG | Y1 | Y2 | Y3 |
+-------+----+----+----+
| A | 6 | 4 | 5 | <- 6 entities w/ categ_y1, 4 w/ categ_y2, 5 w/ categ_y3
| B | 3 | 1 | 10 |
| C | 8 | 4 | 5 |
| NULL | 3 | 3 | 3 |
+-------+----+----+----+
我想我可以通过将值分组到另一列并UNION ALL
结果来实现,但我想知道是否有更快速的&amp;方便的方式,如果我有更多的列/年可以管理(例如20-30个不同的值),它是否可以推广
答案 0 :(得分:1)
有点笨拙,但可能有人有更好的主意。查询首先收集所有不同的类别(from部分中的union-query),然后使用select部分中的专用子查询计算出现的次数。如果已经有一个表已经定义了可用的类别,那么可以省略union-part(我假设categ_y1是这种主类别表的外键)。希望没有很多拼写错误:
select categories.cat,
(select count(categ_y1) from table ty1 where select categories.cat = categ_y1) as y1,
(select count(categ_y2) from table ty2 where select categories.cat = categ_y2) as y2,
(select count(categ_y3) from table ty3 where select categories.cat = categ_y3) as y3
from ( select categ_y1 as cat from table t1
union select categ_y2 as cat from table t2
union select categ_y3 as cat from table t3) categories
答案 1 :(得分:1)
使用jsonb函数将数据(来自问题)转换为以下格式:
select categ, jsonb_object_agg(key, count) as jdata
from (
select value as categ, key, count(*)
from my_table t,
jsonb_each_text(to_jsonb(t)- 'id')
group by 1, 2
) s
group by 1
order by 1;
categ | jdata
-------+-----------------------------------------------
A | {"categ_y1": 2, "categ_y2": 2}
B | {"categ_y1": 1, "categ_y2": 1, "categ_y3": 1}
C | {"categ_y2": 1, "categ_y3": 2}
| {"categ_y1": 1, "categ_y3": 1}
(4 rows)
对于已知(静态)年数,您可以轻松解压缩jsonb列:
select categ, jdata->'categ_y1' as y1, jdata->'categ_y2' as y2, jdata->'categ_y3' as y3
from (
select categ, jsonb_object_agg(key, count) as jdata
from (
select value as categ, key, count(*)
from my_table t,
jsonb_each_text(to_jsonb(t)- 'id')
group by 1, 2
) s
group by 1
) s
order by 1;
categ | y1 | y2 | y3
-------+----+----+----
A | 2 | 2 |
B | 1 | 1 | 1
C | | 1 | 2
| 1 | | 1
(4 rows)
要获得完全动态的解决方案,您可以使用Flatten aggregated key/value pairs from a JSONB field中描述的函数create_jsonb_flat_view()
。
答案 2 :(得分:1)
我会这样做,因为使用union all
后跟聚合:
select categ, sum(categ_y1) as y1, sum(categ_y2) as y2,
sum(categ_y3) as y3
from ((select categ_y1, 1 as categ_y1, 0 as categ_y2, 0 as categ_y3
from t
) union all
(select categ_y2, 0 as categ_y1, 1 as categ_y2, 0 as categ_y3
from t
) union all
(select categ_y3, 0 as categ_y1, 0 as categ_y2, 1 as categ_y3
from t
)
)
group by categ ;