【问题标题】:Concatenation of jsonb elements in postgreSQL with comma separation用逗号分隔 postgreSQL 中的 jsonb 元素的连接
【发布时间】:2021-06-09 18:58:07
【问题描述】:

我想设计一个查询,我可以在其中以受控方式将两个 jsonb 与 postgreSQL 中未知数量/组的元素组合在一起。 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.. 子句提取特殊值。任何见解或提示将不胜感激!

【问题讨论】:

    标签: postgresql jsonb postgresql-json


    【解决方案1】:
    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" 值缺失/空/空的情况

    【讨论】:

    • 谢谢,这很好我没有把这部分放在我的问题中,但我更新了我的查询以删除“特殊”数组元素中的重复项,如下所示:WITH example (a, b) AS (VALUES ('{"a":"foo", "b":"one", "special":"comma"}'::jsonb, '{"a":"bar", "special":"separated"}'::jsonb), ('{"a":"foo", "b":"one", "special":"comma"}'::jsonb, '{"a":"bar", "special":"comma"}'::jsonb) ) SELECT e.a || jsonb_set(e.b, '{special}', to_jsonb(array_to_string(array(select distinct unnest(string_to_array(concat_ws(',', e.a->>'special', e.b->>'special'), ','))), ',')) ) FROM example e;
    【解决方案2】:

    您可以在两个值上使用jsonb_each,然后使用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)
    )
    

    (online demo)

    将任意 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)
    

    【讨论】:

    • 感谢您的回复!这是一种优雅的方法,但我希望只连接“特殊”字段而不是所有字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-05
    • 2013-03-01
    • 2017-09-29
    • 2023-02-10
    • 2014-01-04
    相关资源
    最近更新 更多