如何 select 并计算 PostgreSQL 中 5 列的对或三元组
How to select and count pairs or triplets from 5 columns in PostgreSQL
我有一个 postgreSQL table,我在其中存储了五个不同的列(比如 col1、col2、col3、col4、col5)数字。每行中存储的数字彼此不同。
我想制作一些 select 来给出存在的对以及它们出现的次数(计算它们在行中出现的次数)。
示例:
col1
col2
col3
col4
col5
1
5
10
20
100
5
20
30
40
100
结果(大致是这样的):
pair
total
1,5
1
1,10
1
1,20
1
1,100
1
5,10
1
5,20
2
5,100
2
10,20
1
10,100
1
20,100
2
5,30
1
5,40
1
20,30
1
20,40
1
我可以做一些SQL来执行特定列中的代码:
SELECT count (*) as total, col1, col2
FROM numbers
group by col1, col2;
但这不会给我所有的组合,而且我不知道如何获得其余的组合。此外,这在性能方面可能效率低下。
任何帮助将不胜感激。
此致,
米格尔.
您可以使用 recursive
查询来生成您期望的输出
-- You can change "select 3" to "select 2" or any number you want
with recursive col_join as (select 3),
numbers_row as (
select *, row_number() over () as row
from numbers
),
cte_r as (
select col1 as value, row, 1 as col
from numbers_row
union all
select col2 as value, row, 2 as col
from numbers_row
union all
select col3 as value, row, 3 as col
from numbers_row
union all
select col4 as value, row, 4 as col
from numbers_row
union all
select col5 as value, row, 5 as col
from numbers_row
),
cte as (
select array_agg(value order by col) as value,
row,
col
from cte_r
group by row, col
union all
select c.value || cr1.value as value,
cr1.row,
cr1.col
from cte c,
cte_r cr1
where c.row = cr1.row
and not c.value @> array [cr1.value]
and c.col < cr1.col
and array_length(c.value || cr1.value, 1) <= (select * from col_join)
)
select array_to_string(value, ','), count(*)
from cte
where array_length(value, 1) = (select * from col_join)
group by 1
order by 1
**加入双列的旧方案
with recursive
numbers_row as (
select *, row_number() over () as row from numbers
),
cte_r as (
select col1 as value, row, 1 as col from numbers_row
union all
select col2 as value, row, 2 as col from numbers_row
union all
select col3 as value, row, 3 as col from numbers_row
union all
select col4 as value, row, 4 as col from numbers_row
union all
select col5 as value, row, 5 as col from numbers_row
),
cte as (
select
value as val1,
value as val2,
row,
col
from cte_r
union all
select
c.val1 as val1,
cr.value as val2,
cr.row,
cr.col
from
cte c,
cte_r cr
where c.row = cr.row and c.col = cr.col - 1
)
select val1 || ',' || val2, count(*)
from cte
where val1 <> val2
group by val1, val2, val1 || ',' || val2
order by val1, val2
我有一个 postgreSQL table,我在其中存储了五个不同的列(比如 col1、col2、col3、col4、col5)数字。每行中存储的数字彼此不同。
我想制作一些 select 来给出存在的对以及它们出现的次数(计算它们在行中出现的次数)。
示例:
col1 | col2 | col3 | col4 | col5 |
---|---|---|---|---|
1 | 5 | 10 | 20 | 100 |
5 | 20 | 30 | 40 | 100 |
结果(大致是这样的):
pair | total |
---|---|
1,5 | 1 |
1,10 | 1 |
1,20 | 1 |
1,100 | 1 |
5,10 | 1 |
5,20 | 2 |
5,100 | 2 |
10,20 | 1 |
10,100 | 1 |
20,100 | 2 |
5,30 | 1 |
5,40 | 1 |
20,30 | 1 |
20,40 | 1 |
我可以做一些SQL来执行特定列中的代码:
SELECT count (*) as total, col1, col2
FROM numbers
group by col1, col2;
但这不会给我所有的组合,而且我不知道如何获得其余的组合。此外,这在性能方面可能效率低下。
任何帮助将不胜感激。
此致, 米格尔.
您可以使用 recursive
查询来生成您期望的输出
-- You can change "select 3" to "select 2" or any number you want
with recursive col_join as (select 3),
numbers_row as (
select *, row_number() over () as row
from numbers
),
cte_r as (
select col1 as value, row, 1 as col
from numbers_row
union all
select col2 as value, row, 2 as col
from numbers_row
union all
select col3 as value, row, 3 as col
from numbers_row
union all
select col4 as value, row, 4 as col
from numbers_row
union all
select col5 as value, row, 5 as col
from numbers_row
),
cte as (
select array_agg(value order by col) as value,
row,
col
from cte_r
group by row, col
union all
select c.value || cr1.value as value,
cr1.row,
cr1.col
from cte c,
cte_r cr1
where c.row = cr1.row
and not c.value @> array [cr1.value]
and c.col < cr1.col
and array_length(c.value || cr1.value, 1) <= (select * from col_join)
)
select array_to_string(value, ','), count(*)
from cte
where array_length(value, 1) = (select * from col_join)
group by 1
order by 1
**加入双列的旧方案
with recursive
numbers_row as (
select *, row_number() over () as row from numbers
),
cte_r as (
select col1 as value, row, 1 as col from numbers_row
union all
select col2 as value, row, 2 as col from numbers_row
union all
select col3 as value, row, 3 as col from numbers_row
union all
select col4 as value, row, 4 as col from numbers_row
union all
select col5 as value, row, 5 as col from numbers_row
),
cte as (
select
value as val1,
value as val2,
row,
col
from cte_r
union all
select
c.val1 as val1,
cr.value as val2,
cr.row,
cr.col
from
cte c,
cte_r cr
where c.row = cr.row and c.col = cr.col - 1
)
select val1 || ',' || val2, count(*)
from cte
where val1 <> val2
group by val1, val2, val1 || ',' || val2
order by val1, val2