在 postgreSQL 中用逗号分隔连接 jsonb 元素
Concatenation of jsonb elements in postgreSQL with comma separation
我想设计一个查询,我可以在其中以受控方式将两个 jsonb 与 postgreSQL 中的未知 number/set 元素组合起来。 jsonb 运算符 ||
几乎完全符合我的目的,但对于其中一个 jsonb 元素,我想用逗号连接和分隔两个值,而不是让第二个 jsonb 的值覆盖第一个的值。例如:
'{"a":"foo", "b":"one", "special":"comma"}'::jsonb || '{"a":"bar", "special":"separated"}'::jsonb → '{"a":"bar", "b":"one", "special":"comma,separated"}'
我当前的查询如下:
INSERT INTO table AS t (col1, col2, col3_jsonb)
VALUES ("first", "second", '["a":"bar", "special":"separated"]'::jsonb))
ON CONFLICT ON CONSTRAINT unique_entries DO UPDATE
SET col3_jsonb = excluded.col3_jsonb || t.col3_jsonb
RETURNING id;
这导致 col3_jsonb
的 jsonb 元素的值 special 设置为 separated
而不是所需的 comma,separated
。我知道这是按照记录工作的串联运算符,但我不确定如何以不同的方式处理 jsonb 的一个元素,而不是尝试在查询的其他地方使用 WITH..
子句提取特殊值。任何见解或提示将不胜感激!
您可以使用 jsonb_each
on the two values followed by jsonb_object_agg
将它们放回对象中:
…
SET col3_jsonb = (
SELECT jsonb_object_agg(
key,
COALESCE(to_jsonb((old.value->>0) || ',' || (new.value->>0)), new.value, old.value)
)
FROM jsonb_each(example.old_obj) old
FULL OUTER JOIN jsonb_each(example.new_obj) new USING (key)
)
将任意 JSON 值转换为所需的可连接字符串 a trick。如果您知道所有对象属性都有字符串值,则可以使用 jsonb_each_text
来简化:
SELECT jsonb_object_agg(
key,
COALESCE(old.value || ',' || new.value, new.value, old.value)
)
FROM jsonb_each_text(example.old_obj) old
FULL OUTER JOIN jsonb_each_text(example.new_obj) new USING (key)
with t(a,b) as (values(
'{"a":"foo", "b":"one", "special":"comma"}'::jsonb,
'{"a":"bar", "special":"separated"}'::jsonb))
select
a || jsonb_set(b, '{special}',
to_jsonb(concat_ws(',', nullif(a->>'special', ''), nullif(b->>'special', ''))))
from t;
┌────────────────────────────────────────────────────────┐
│ ?column? │
├────────────────────────────────────────────────────────┤
│ {"a": "bar", "b": "one", "special": "comma,separated"} │
└────────────────────────────────────────────────────────┘
nullif()
和 concat_ws()
函数需要一个或两个 "special"
值是 missing/null/empty
的情况
我想设计一个查询,我可以在其中以受控方式将两个 jsonb 与 postgreSQL 中的未知 number/set 元素组合起来。 jsonb 运算符 ||
几乎完全符合我的目的,但对于其中一个 jsonb 元素,我想用逗号连接和分隔两个值,而不是让第二个 jsonb 的值覆盖第一个的值。例如:
'{"a":"foo", "b":"one", "special":"comma"}'::jsonb || '{"a":"bar", "special":"separated"}'::jsonb → '{"a":"bar", "b":"one", "special":"comma,separated"}'
我当前的查询如下:
INSERT INTO table AS t (col1, col2, col3_jsonb)
VALUES ("first", "second", '["a":"bar", "special":"separated"]'::jsonb))
ON CONFLICT ON CONSTRAINT unique_entries DO UPDATE
SET col3_jsonb = excluded.col3_jsonb || t.col3_jsonb
RETURNING id;
这导致 col3_jsonb
的 jsonb 元素的值 special 设置为 separated
而不是所需的 comma,separated
。我知道这是按照记录工作的串联运算符,但我不确定如何以不同的方式处理 jsonb 的一个元素,而不是尝试在查询的其他地方使用 WITH..
子句提取特殊值。任何见解或提示将不胜感激!
您可以使用 jsonb_each
on the two values followed by jsonb_object_agg
将它们放回对象中:
…
SET col3_jsonb = (
SELECT jsonb_object_agg(
key,
COALESCE(to_jsonb((old.value->>0) || ',' || (new.value->>0)), new.value, old.value)
)
FROM jsonb_each(example.old_obj) old
FULL OUTER JOIN jsonb_each(example.new_obj) new USING (key)
)
将任意 JSON 值转换为所需的可连接字符串 a trick。如果您知道所有对象属性都有字符串值,则可以使用 jsonb_each_text
来简化:
SELECT jsonb_object_agg(
key,
COALESCE(old.value || ',' || new.value, new.value, old.value)
)
FROM jsonb_each_text(example.old_obj) old
FULL OUTER JOIN jsonb_each_text(example.new_obj) new USING (key)
with t(a,b) as (values(
'{"a":"foo", "b":"one", "special":"comma"}'::jsonb,
'{"a":"bar", "special":"separated"}'::jsonb))
select
a || jsonb_set(b, '{special}',
to_jsonb(concat_ws(',', nullif(a->>'special', ''), nullif(b->>'special', ''))))
from t;
┌────────────────────────────────────────────────────────┐
│ ?column? │
├────────────────────────────────────────────────────────┤
│ {"a": "bar", "b": "one", "special": "comma,separated"} │
└────────────────────────────────────────────────────────┘
nullif()
和 concat_ws()
函数需要一个或两个 "special"
值是 missing/null/empty