使用 Postgresql 生成多个交叉连接

Generate multiple cross joins with Postgresql

我有一个 JSON 数组,其中包含两个成员名为 firstsecond 的对象。每个都有一个值数组。我想为一个给定对象生成 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;

当然,具有多个对象的相同查询不起作用,因为它在 firstsecond 的所有值之间执行 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)