如何计算特定值在每列上出现的次数并按范围分组
How to count how many times a specific value appeared on each columns and group by range
我是 postgres 的新手,我有一个问题:
我有一个包含 100 列的 table。我需要计算每一列的值并计算它们出现的次数,这样我就可以根据它们适合的范围进行分组
我有一个 table 这样的(100 列)
+------+------+------+------+------+---------+--------+
| Name | PRB0 | PRB1 | PRB2 | PRB3 | ....... | PRB100 |
+------+------+------+------+------+---------+--------+
| A | 15 | 6 | 47 | 54 | ..... | 8 |
| B | 25 | 22 | 84 | 86 | ..... | 76 |
| C | 57 | 57 | 96 | 38 | ..... | 28 |
+------+------+------+------+------+---------+--------+
并且需要这样的输出
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
| Name | Count 0 to 20 | Count 21 to 40 | Count 41 to 60 | Count 61 to 70 | ... | Count 81 to 100 | |
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
| A | 5 | 46 | 87 | 34 | ... | 98 | |
| B | 5 | 2 | 34 | 56 | ... | 36 | |
| C | 7 | 17 | 56 | 78 | ... | 88 | |
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
对于名称 A,我们有:
- 0到20之间出现5次
- 46次出现了21到40之间的数
- 41到60之间出现了86次
基本上,我需要像 Excel 上的函数 COUNTIFS 这样的东西。在 excel 我们只需要指定列的范围和条件。
您可以使用横向联接取消透视,然后聚合:
select
name,
count(*) filter(where prb between 0 and 20) cnt_00_20,
count(*) filter(where prb between 21 and 50) cnt_21_20,
...,
count(*) filter(where prb between 81 and 100) cnt_81_100
from mytable t
cross join lateral (values(t.prb0), (t.prb1), ..., (t.prb100)) p(prb)
group by name
但是请注意,这仍然需要您枚举 values()
table 构造函数中的所有列。如果你想要完全动态的东西,你可以使用 json 代替。这个想法是使用 to_jsonb()
将每条记录转换为 json 对象,然后使用 jsonb_each()
转换为行;然后你可以进行条件聚合。
select
name,
count(*) filter(where prb::int between 0 and 20) cnt_00_20,
count(*) filter(where prb::int between 21 and 50) cnt_21_20,
...,
count(*) filter(where prb::int between 81 and 100) cnt_81_100
from mytable t
cross join lateral to_jsonb(t) j(js)
cross join lateral jsonb_each( j.js - 'name') r(col, prb)
group by name
我是 postgres 的新手,我有一个问题:
我有一个包含 100 列的 table。我需要计算每一列的值并计算它们出现的次数,这样我就可以根据它们适合的范围进行分组
我有一个 table 这样的(100 列)
+------+------+------+------+------+---------+--------+
| Name | PRB0 | PRB1 | PRB2 | PRB3 | ....... | PRB100 |
+------+------+------+------+------+---------+--------+
| A | 15 | 6 | 47 | 54 | ..... | 8 |
| B | 25 | 22 | 84 | 86 | ..... | 76 |
| C | 57 | 57 | 96 | 38 | ..... | 28 |
+------+------+------+------+------+---------+--------+
并且需要这样的输出
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
| Name | Count 0 to 20 | Count 21 to 40 | Count 41 to 60 | Count 61 to 70 | ... | Count 81 to 100 | |
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
| A | 5 | 46 | 87 | 34 | ... | 98 | |
| B | 5 | 2 | 34 | 56 | ... | 36 | |
| C | 7 | 17 | 56 | 78 | ... | 88 | |
+------+---------------+----------------+----------------+----------------+-----+-----------------+--+
对于名称 A,我们有:
- 0到20之间出现5次
- 46次出现了21到40之间的数
- 41到60之间出现了86次
基本上,我需要像 Excel 上的函数 COUNTIFS 这样的东西。在 excel 我们只需要指定列的范围和条件。
您可以使用横向联接取消透视,然后聚合:
select
name,
count(*) filter(where prb between 0 and 20) cnt_00_20,
count(*) filter(where prb between 21 and 50) cnt_21_20,
...,
count(*) filter(where prb between 81 and 100) cnt_81_100
from mytable t
cross join lateral (values(t.prb0), (t.prb1), ..., (t.prb100)) p(prb)
group by name
但是请注意,这仍然需要您枚举 values()
table 构造函数中的所有列。如果你想要完全动态的东西,你可以使用 json 代替。这个想法是使用 to_jsonb()
将每条记录转换为 json 对象,然后使用 jsonb_each()
转换为行;然后你可以进行条件聚合。
select
name,
count(*) filter(where prb::int between 0 and 20) cnt_00_20,
count(*) filter(where prb::int between 21 and 50) cnt_21_20,
...,
count(*) filter(where prb::int between 81 and 100) cnt_81_100
from mytable t
cross join lateral to_jsonb(t) j(js)
cross join lateral jsonb_each( j.js - 'name') r(col, prb)
group by name