将嵌套的 JSONB 数组连接成单个字符串
Concatenating Nested JSONB Arrays into a Single String
在 Postgres 11 数据库中,有一个 table (traces
),其中有一列类型为 JSONB
(trace
)。 JSON 值始终是以下形式的嵌套数组:
[ ["a", "b"], ... ]
每一行的数组中至少有一个子元素。我想添加第二列(已计算,但现在一个简单的查询就足以满足这种情况),其中包含
形式的数组列的字符串表示形式
a.b c.d.e
来自 [["a","b"],["c","d","e"]]
的数组值。
我已经尝试了几件事,但我可能在这里遗漏了一些理论。在我看来,这将涉及某种双重聚合,一次用于每个嵌套数组,然后再次用于最外层数组。我如何在查询中表达它(如果这是正确的方法)?
我的出发点是首先访问所有嵌套数组的查询:
SELECT nested FROM traces, jsonb_array_elements(trace) nested;
它 return 嵌套数组列表,我认为 nested
是 JSONB
。我继续使用这样的方法:
SELECT
trace,
array_to_string(array_agg(nested), ' ')
FROM traces,
jsonb_array_elements(trace) nested
GROUP BY trace;
但我 运行 遇到无法 "nest" 聚合函数的问题。
SELECT
trace,
string_agg(point_separated, ' ') -- 4
FROM (
SELECT
trace,
string_agg(second_level, '.') AS point_separated -- 3
FROM
traces,
jsonb_array_elements(trace) as first_level, -- 1
jsonb_array_elements_text(first_level) as second_level -- 2
GROUP BY trace, first_level.value
) s
GROUP BY trace
- 使用
jsonb_array_elements()
将嵌套数组扩展为每个嵌套数组一条记录
- 通过第二次调用此函数,将嵌套数组的元素扩展为每个元素一条记录。
目前的中间结果:
trace | value | value
:---------------------------- | :-------------- | :----
[["a", "b"], ["c", "d", "e"]] | ["a", "b"] | a
[["a", "b"], ["c", "d", "e"]] | ["a", "b"] | b
[["a", "b"], ["c", "d", "e"]] | ["c", "d", "e"] | c
[["a", "b"], ["c", "d", "e"]] | ["c", "d", "e"] | d
[["a", "b"], ["c", "d", "e"]] | ["c", "d", "e"] | e
[["e", "f", "g"], ["h", "i"]] | ["e", "f", "g"] | e
[["e", "f", "g"], ["h", "i"]] | ["e", "f", "g"] | f
[["e", "f", "g"], ["h", "i"]] | ["e", "f", "g"] | g
[["e", "f", "g"], ["h", "i"]] | ["h", "i"] | h
[["e", "f", "g"], ["h", "i"]] | ["h", "i"] | i
- 使用
GROUP BY
和 string_agg()
将内部元素聚合成以点分隔的字符串
- 使用 this 的第二次调用将这些结果聚合成 space 分隔的字符串。
如果聚合字符串的顺序对您很重要,您需要添加行计数,因为如果您不告诉它们,像 string_agg()
这样的聚合不能保证一定的顺序。
像jsonb_array_elements()
这样的集合返回函数支持添加这样一个行号的WITH ORDINALITY
扩展。这可用于将 ORDER BY
添加到 string_agg()
函数中:
SELECT
trace,
string_agg(point_separated, ' ' ORDER BY number)
FROM (
SELECT
trace,
first_level.number,
string_agg(second_level.val, '.'
ORDER BY first_level.number, second_level.number) AS point_separated
FROM
traces,
jsonb_array_elements(trace) WITH ORDINALITY as first_level(val, number),
jsonb_array_elements_text(first_level.val) WITH ORDINALITY as second_level(val, number)
GROUP BY trace, first_level.val, first_level.number
) s
GROUP BY trace
在 Postgres 11 数据库中,有一个 table (traces
),其中有一列类型为 JSONB
(trace
)。 JSON 值始终是以下形式的嵌套数组:
[ ["a", "b"], ... ]
每一行的数组中至少有一个子元素。我想添加第二列(已计算,但现在一个简单的查询就足以满足这种情况),其中包含
形式的数组列的字符串表示形式a.b c.d.e
来自 [["a","b"],["c","d","e"]]
的数组值。
我已经尝试了几件事,但我可能在这里遗漏了一些理论。在我看来,这将涉及某种双重聚合,一次用于每个嵌套数组,然后再次用于最外层数组。我如何在查询中表达它(如果这是正确的方法)?
我的出发点是首先访问所有嵌套数组的查询:
SELECT nested FROM traces, jsonb_array_elements(trace) nested;
它 return 嵌套数组列表,我认为 nested
是 JSONB
。我继续使用这样的方法:
SELECT
trace,
array_to_string(array_agg(nested), ' ')
FROM traces,
jsonb_array_elements(trace) nested
GROUP BY trace;
但我 运行 遇到无法 "nest" 聚合函数的问题。
SELECT
trace,
string_agg(point_separated, ' ') -- 4
FROM (
SELECT
trace,
string_agg(second_level, '.') AS point_separated -- 3
FROM
traces,
jsonb_array_elements(trace) as first_level, -- 1
jsonb_array_elements_text(first_level) as second_level -- 2
GROUP BY trace, first_level.value
) s
GROUP BY trace
- 使用
jsonb_array_elements()
将嵌套数组扩展为每个嵌套数组一条记录
- 通过第二次调用此函数,将嵌套数组的元素扩展为每个元素一条记录。
目前的中间结果:
trace | value | value
:---------------------------- | :-------------- | :----
[["a", "b"], ["c", "d", "e"]] | ["a", "b"] | a
[["a", "b"], ["c", "d", "e"]] | ["a", "b"] | b
[["a", "b"], ["c", "d", "e"]] | ["c", "d", "e"] | c
[["a", "b"], ["c", "d", "e"]] | ["c", "d", "e"] | d
[["a", "b"], ["c", "d", "e"]] | ["c", "d", "e"] | e
[["e", "f", "g"], ["h", "i"]] | ["e", "f", "g"] | e
[["e", "f", "g"], ["h", "i"]] | ["e", "f", "g"] | f
[["e", "f", "g"], ["h", "i"]] | ["e", "f", "g"] | g
[["e", "f", "g"], ["h", "i"]] | ["h", "i"] | h
[["e", "f", "g"], ["h", "i"]] | ["h", "i"] | i
- 使用
GROUP BY
和string_agg()
将内部元素聚合成以点分隔的字符串
- 使用 this 的第二次调用将这些结果聚合成 space 分隔的字符串。
如果聚合字符串的顺序对您很重要,您需要添加行计数,因为如果您不告诉它们,像 string_agg()
这样的聚合不能保证一定的顺序。
像jsonb_array_elements()
这样的集合返回函数支持添加这样一个行号的WITH ORDINALITY
扩展。这可用于将 ORDER BY
添加到 string_agg()
函数中:
SELECT
trace,
string_agg(point_separated, ' ' ORDER BY number)
FROM (
SELECT
trace,
first_level.number,
string_agg(second_level.val, '.'
ORDER BY first_level.number, second_level.number) AS point_separated
FROM
traces,
jsonb_array_elements(trace) WITH ORDINALITY as first_level(val, number),
jsonb_array_elements_text(first_level.val) WITH ORDINALITY as second_level(val, number)
GROUP BY trace, first_level.val, first_level.number
) s
GROUP BY trace