SQL - 分区的笛卡尔积
SQL - cartesian product of PARTITIONs
有一个非常复杂的查询,我一个人无法解决。在查询的table中有5列:PK_ID
,它是值的唯一标识符,ID
,它连接一组聚合值,count
,其中表示应该聚合多少个值组(如果没有足够的值,则应从查询结果中省略具有 ID
的组), num
表示聚合的数量组内的值,以及要聚合的 value
。
(Table T1)
PK_ID | ID | num | count | value
------+-------+-------+--------+--------
1 | 1 | 1 | 3 | A
------+-------+-------+--------+--------
2 | 1 | 2 | 3 | B
------+-------+-------+--------+--------
3 | 1 | 3 | 3 | C
------+-------+-------+--------+--------
4 | 1 | 1 | 3 | D
------+-------+-------+--------+--------
5 | 1 | 3 | 3 | E
------+-------+-------+--------+--------
6 | 1 | 2 | 3 | F
------+-------+-------+--------+--------
7 | 1 | 3 | 3 | G
------+-------+-------+--------+--------
8 | 2 | 1 | 2 | H
------+-------+-------+--------+--------
9 | 2 | 2 | 2 | I
------+-------+-------+--------+--------
10 | 2 | 1 | 2 | J
------+-------+-------+--------+--------
11 | 3 | 1 | 5 | X
此类查询的结果将是:
PK_ID | T1_ID | cross_aggr | T1_PK_IDs
------+-------+------------+-----------
1 | 1 | {A, B, C} | {1, 2, 3}
------+-------+------------+-----------
2 | 1 | {A, B, E} | {1, 2, 5}
------+-------+------------+-----------
3 | 1 | {A, B, G} | {1, 2, 7}
------+-------+------------+-----------
4 | 1 | {A, F, C} | {1, 6, 3}
------+-------+------------+-----------
5 | 1 | {A, F, E} | {1, 6, 5}
------+-------+------------+-----------
6 | 1 | {A, F, G} | {1, 6, 7}
------+-------+------------+-----------
7 | 1 | {D, B, C} | {4, 2, 3}
------+-------+------------+-----------
8 | 1 | {D, B, E} | {4, 2, 5}
------+-------+------------+-----------
9 | 1 | {D, B, G} | {4, 2, 7}
------+-------+------------+-----------
10 | 1 | {D, F, C} | {4, 6, 3}
------+-------+------------+-----------
11 | 1 | {D, F, E} | {4, 6, 5}
------+-------+------------+-----------
12 | 1 | {D, F, G} | {4, 6, 7}
------+-------+------------+-----------
13 | 2 | {H, I} | {8, 9}
------+-------+------------+-----------
14 | 2 | {J, I} | {10, 9}
因此它返回了每个组内 value
的所有可能组合,由 ID
定义并由 count
描述,并且这些值按每个个体的顺序聚合 num
.
看起来我必须使用 CROSS JOIN
(与笛卡尔积在线性代数中的工作方式相同),但 CROSS JOIN
似乎只有在 JOIN
ed tables 是预先知道的,但是有 count
并发症。 count
本身可能(我的意思是它不会,但它可以)范围从 2
到 infinity
。
我想过用 WINDOW
函数、PARTITION BY
、ID
和 num
来处理它,但之后我就卡住了,因为那里似乎没有办法得到这些分区的笛卡尔积。
我应该收工并寻找另一种方法来处理数据,还是有办法编写这样的查询?
这看起来像是一个图遍历问题 - 需要递归查询。
with recursive cte as (
select id, num, cnt, 1 as lvl,
array[value::text] as arr_values,
array[pk_id::int] as arr_pk_id
from mytable where num = 1
union all
select c.id, t.num, c.cnt, c.lvl + 1,
c.arr_values || t.value::text,
c.arr_pk_id || t.pk_id
from cte c
inner join mytable t
on t.id = c.id
and t.num = c.num + 1
and t.num <= c.cnt
)
select id, arr_values, arr_pk_id
from cte
where array_length(arr_pk_id, 1) = cnt
order by arr_pk_id
对于每个 id
,递归查询从 num
1
开始并遵循所有可能的路径。外部查询仅在路径末尾进行过滤。
id | arr_values | arr_pk_id
-: | :--------- | :--------
1 | {A,B,C} | {1,2,3}
1 | {A,B,E} | {1,2,5}
1 | {A,B,G} | {1,2,7}
1 | {A,F,C} | {1,6,3}
1 | {A,F,E} | {1,6,5}
1 | {A,F,G} | {1,6,7}
1 | {D,B,C} | {4,2,3}
1 | {D,B,E} | {4,2,5}
1 | {D,B,G} | {4,2,7}
1 | {D,F,C} | {4,6,3}
1 | {D,F,E} | {4,6,5}
1 | {D,F,G} | {4,6,7}
2 | {H,I} | {8,9}
2 | {J,I} | {10,9}
有一个非常复杂的查询,我一个人无法解决。在查询的table中有5列:PK_ID
,它是值的唯一标识符,ID
,它连接一组聚合值,count
,其中表示应该聚合多少个值组(如果没有足够的值,则应从查询结果中省略具有 ID
的组), num
表示聚合的数量组内的值,以及要聚合的 value
。
(Table T1)
PK_ID | ID | num | count | value
------+-------+-------+--------+--------
1 | 1 | 1 | 3 | A
------+-------+-------+--------+--------
2 | 1 | 2 | 3 | B
------+-------+-------+--------+--------
3 | 1 | 3 | 3 | C
------+-------+-------+--------+--------
4 | 1 | 1 | 3 | D
------+-------+-------+--------+--------
5 | 1 | 3 | 3 | E
------+-------+-------+--------+--------
6 | 1 | 2 | 3 | F
------+-------+-------+--------+--------
7 | 1 | 3 | 3 | G
------+-------+-------+--------+--------
8 | 2 | 1 | 2 | H
------+-------+-------+--------+--------
9 | 2 | 2 | 2 | I
------+-------+-------+--------+--------
10 | 2 | 1 | 2 | J
------+-------+-------+--------+--------
11 | 3 | 1 | 5 | X
此类查询的结果将是:
PK_ID | T1_ID | cross_aggr | T1_PK_IDs
------+-------+------------+-----------
1 | 1 | {A, B, C} | {1, 2, 3}
------+-------+------------+-----------
2 | 1 | {A, B, E} | {1, 2, 5}
------+-------+------------+-----------
3 | 1 | {A, B, G} | {1, 2, 7}
------+-------+------------+-----------
4 | 1 | {A, F, C} | {1, 6, 3}
------+-------+------------+-----------
5 | 1 | {A, F, E} | {1, 6, 5}
------+-------+------------+-----------
6 | 1 | {A, F, G} | {1, 6, 7}
------+-------+------------+-----------
7 | 1 | {D, B, C} | {4, 2, 3}
------+-------+------------+-----------
8 | 1 | {D, B, E} | {4, 2, 5}
------+-------+------------+-----------
9 | 1 | {D, B, G} | {4, 2, 7}
------+-------+------------+-----------
10 | 1 | {D, F, C} | {4, 6, 3}
------+-------+------------+-----------
11 | 1 | {D, F, E} | {4, 6, 5}
------+-------+------------+-----------
12 | 1 | {D, F, G} | {4, 6, 7}
------+-------+------------+-----------
13 | 2 | {H, I} | {8, 9}
------+-------+------------+-----------
14 | 2 | {J, I} | {10, 9}
因此它返回了每个组内 value
的所有可能组合,由 ID
定义并由 count
描述,并且这些值按每个个体的顺序聚合 num
.
看起来我必须使用 CROSS JOIN
(与笛卡尔积在线性代数中的工作方式相同),但 CROSS JOIN
似乎只有在 JOIN
ed tables 是预先知道的,但是有 count
并发症。 count
本身可能(我的意思是它不会,但它可以)范围从 2
到 infinity
。
我想过用 WINDOW
函数、PARTITION BY
、ID
和 num
来处理它,但之后我就卡住了,因为那里似乎没有办法得到这些分区的笛卡尔积。
我应该收工并寻找另一种方法来处理数据,还是有办法编写这样的查询?
这看起来像是一个图遍历问题 - 需要递归查询。
with recursive cte as (
select id, num, cnt, 1 as lvl,
array[value::text] as arr_values,
array[pk_id::int] as arr_pk_id
from mytable where num = 1
union all
select c.id, t.num, c.cnt, c.lvl + 1,
c.arr_values || t.value::text,
c.arr_pk_id || t.pk_id
from cte c
inner join mytable t
on t.id = c.id
and t.num = c.num + 1
and t.num <= c.cnt
)
select id, arr_values, arr_pk_id
from cte
where array_length(arr_pk_id, 1) = cnt
order by arr_pk_id
对于每个 id
,递归查询从 num
1
开始并遵循所有可能的路径。外部查询仅在路径末尾进行过滤。
id | arr_values | arr_pk_id -: | :--------- | :-------- 1 | {A,B,C} | {1,2,3} 1 | {A,B,E} | {1,2,5} 1 | {A,B,G} | {1,2,7} 1 | {A,F,C} | {1,6,3} 1 | {A,F,E} | {1,6,5} 1 | {A,F,G} | {1,6,7} 1 | {D,B,C} | {4,2,3} 1 | {D,B,E} | {4,2,5} 1 | {D,B,G} | {4,2,7} 1 | {D,F,C} | {4,6,3} 1 | {D,F,E} | {4,6,5} 1 | {D,F,G} | {4,6,7} 2 | {H,I} | {8,9} 2 | {J,I} | {10,9}