You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL更新jsonb字段时如何不覆盖已有键实现值合并

PostgreSQL jsonb自定义合并方案

你可以通过自定义PL/pgSQL函数实现指定的合并规则,不需要提前知晓待更新的键名,函数会自动遍历新JSON对象的所有键值对做处理:

步骤1:创建自定义合并函数

CREATE OR REPLACE FUNCTION jsonb_merge_keep_duplicates(old_json jsonb, new_json jsonb)
RETURNS jsonb AS $$
DECLARE
    key text;
    new_val jsonb;
    old_val jsonb;
BEGIN
    -- 遍历新JSON对象的所有键值对
    FOR key, new_val IN SELECT * FROM jsonb_each(new_json) LOOP
        old_val := old_json -> key;
        -- 原JSON不存在对应键,直接插入
        IF old_val IS NULL THEN
            old_json := jsonb_set(old_json, ARRAY[key], new_val);
        ELSE
            -- 原键已存在,将旧值转为数组后追加新值
            IF jsonb_typeof(old_val) != 'array' THEN
                old_val := jsonb_build_array(old_val);
            END IF;
            old_json := jsonb_set(old_json, ARRAY[key], old_val || new_val);
        END IF;
    END LOOP;
    RETURN old_json;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

步骤2:使用函数执行更新

替换原来的||运算符为自定义函数即可:

UPDATE tmp_1 
   SET jb_value = jsonb_merge_keep_duplicates(jb_value, '{"foo_bar":4, "foo_foo_bar":4}'::jsonb)
 WHERE id = 1;

结果验证

执行查询确认结果符合预期:

SELECT jb_value FROM tmp_1 WHERE id = 1;
-- 输出:{"foo": 1, "bar": 2, "foo_bar": [3, 4], "foo_foo_bar": 4}

补充说明

  • 上述函数仅合并顶层键,如果你需要递归处理嵌套JSON对象,可在判断旧值类型为object时递归调用该函数
  • 函数标记为IMMUTABLE,输入固定时输出结果固定,支持PostgreSQL的查询优化,也可安全用于索引表达式

内容的提问来源于stack exchange,提问作者w8forw8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 15:36:02