使用 Postgresql 生成多个交叉连接
Generate multiple cross joins with Postgresql
我有一个 JSON 数组,其中包含两个成员名为 first
和 second
的对象。每个都有一个值数组。我想为一个给定对象生成 first
中的值与 second
中的值之间的所有可能组合的行,然后对下一个对象执行相同的操作,依此类推。可以有任意数量的对象。数组中的某些值可能相同。
示例 1:
[{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]}]
应该给我
first | second
-----------+--------
1 - one | 1
1 - one | 2
2 - two | 1
2 - two | 2
3 - three | 1
3 - three | 2
(6 rows)
示例 2:
[
{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]},
{"first":["4 - four", "5 - five"], "second": [10]}
]
应该给我
first | second
-----------+--------
1 - one | 1
1 - one | 2
2 - two | 1
2 - two | 2
3 - three | 1
3 - three | 2
4 - four | 10
5 - five | 10
(8 rows)
当只有一个对象时,以下查询运行良好。
with t1(j) as (
select jsonb_array_elements('[{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]}]'::jsonb)
),
t2(first, second) as (
select * from
(select jsonb_array_elements_text(j->'first') from t1) as first
cross join
(select jsonb_array_elements_text(j->'second')::smallint from t1) as second
)
select * from t2 order by first, second;
当然,具有多个对象的相同查询不起作用,因为它在 first
和 second
的所有值之间执行 cross join
而不是尊重对。
with t1(j) as (
select jsonb_array_elements('[{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]},{"first":["4 - four", "5 - five"], "second": [10]}]'::jsonb)
),
t2(first, second) as (
select * from
(select jsonb_array_elements_text(j->'first') from t1) as first
cross join
(select jsonb_array_elements_text(j->'second')::smallint from t1) as second
)
select * from t2 order by first, second;
first | second
-----------+--------
1 - one | 1
1 - one | 2
1 - one | 10
2 - two | 1
2 - two | 2
2 - two | 10
3 - three | 1
3 - three | 2
3 - three | 10
4 - four | 1
4 - four | 2
4 - four | 10
5 - five | 1
5 - five | 2
5 - five | 10
(15 rows)
我应该如何更改查询以使其工作?我想过一个递归的 CTE,但不知道怎么写。
在您的原始查询中,您通过执行子查询打破了关系。像这样重写它:
SELECT *
FROM jsonb_array_elements('[
{"first": ["1 - one", "2 - two", "3 - three"], "second": [1, 2]},
{"first": ["4 - four", "5 - five"], "second": [10]}
]') AS o,
LATERAL jsonb_array_elements(o.value->'first') AS f(first),
LATERAL jsonb_array_elements(o.value->'second') AS s(second)
我有一个 JSON 数组,其中包含两个成员名为 first
和 second
的对象。每个都有一个值数组。我想为一个给定对象生成 first
中的值与 second
中的值之间的所有可能组合的行,然后对下一个对象执行相同的操作,依此类推。可以有任意数量的对象。数组中的某些值可能相同。
示例 1:
[{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]}]
应该给我
first | second
-----------+--------
1 - one | 1
1 - one | 2
2 - two | 1
2 - two | 2
3 - three | 1
3 - three | 2
(6 rows)
示例 2:
[
{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]},
{"first":["4 - four", "5 - five"], "second": [10]}
]
应该给我
first | second
-----------+--------
1 - one | 1
1 - one | 2
2 - two | 1
2 - two | 2
3 - three | 1
3 - three | 2
4 - four | 10
5 - five | 10
(8 rows)
当只有一个对象时,以下查询运行良好。
with t1(j) as (
select jsonb_array_elements('[{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]}]'::jsonb)
),
t2(first, second) as (
select * from
(select jsonb_array_elements_text(j->'first') from t1) as first
cross join
(select jsonb_array_elements_text(j->'second')::smallint from t1) as second
)
select * from t2 order by first, second;
当然,具有多个对象的相同查询不起作用,因为它在 first
和 second
的所有值之间执行 cross join
而不是尊重对。
with t1(j) as (
select jsonb_array_elements('[{"first":["1 - one", "2 - two", "3 - three"], "second": [1, 2]},{"first":["4 - four", "5 - five"], "second": [10]}]'::jsonb)
),
t2(first, second) as (
select * from
(select jsonb_array_elements_text(j->'first') from t1) as first
cross join
(select jsonb_array_elements_text(j->'second')::smallint from t1) as second
)
select * from t2 order by first, second;
first | second
-----------+--------
1 - one | 1
1 - one | 2
1 - one | 10
2 - two | 1
2 - two | 2
2 - two | 10
3 - three | 1
3 - three | 2
3 - three | 10
4 - four | 1
4 - four | 2
4 - four | 10
5 - five | 1
5 - five | 2
5 - five | 10
(15 rows)
我应该如何更改查询以使其工作?我想过一个递归的 CTE,但不知道怎么写。
在您的原始查询中,您通过执行子查询打破了关系。像这样重写它:
SELECT *
FROM jsonb_array_elements('[
{"first": ["1 - one", "2 - two", "3 - three"], "second": [1, 2]},
{"first": ["4 - four", "5 - five"], "second": [10]}
]') AS o,
LATERAL jsonb_array_elements(o.value->'first') AS f(first),
LATERAL jsonb_array_elements(o.value->'second') AS s(second)