PostgreSQL嵌套JSON分表插入及动态SQL format报错求助
问题根因
你写的动态SQL报too few arguments for format错误,核心原因是format()函数内写了3个%I占位符,但调用时仅传入了1个tb_n参数,参数数量不匹配。除此之外原代码还有3个逻辑问题:
- JSON顶层键名是
firstt、secondt,和目标表名Table1、Table2不对应,直接用键名当表名会报表不存在的错误 - 遍历键再重复关联test表的写法冗余,性能差
- 字符串值比较的位置误用了标识符占位符
%I,值匹配应该用字符串占位符%L
方案1:静态插入(固定映射场景推荐,最稳定)
如果你的键和表的对应关系是固定的(firstt→Table1,secondt→Table2),完全不需要写PL/pgSQL动态块,两条普通SQL就能完成插入,不会出现格式参数不匹配这类动态SQL特有问题:
-- 写入firstt数组数据到Table1 INSERT INTO Table1 (id, sd, v) SELECT (json_populate_recordset(null::Table1, json_array -> 'firstt')).* FROM test; -- 写入secondt数组数据到Table2 INSERT INTO Table2 (id, sd, v) SELECT (json_populate_recordset(null::Table2, json_array -> 'secondt')).* FROM test;
该写法会自动处理test表中所有行存储的JSON数据,不需要额外写循环。你之前用
->>能正常查询但json_populate_recordset插入失败,本质是之前多写了一层cross join json_array_elements拆分数组,实际上直接把目标键对应的数组传给json_populate_recordset即可,不需要额外拆层。
方案2:修正后的动态SQL(需要动态扩展键场景用)
如果后续会新增同结构的顶层键,需要动态适配插入逻辑,修正后的代码如下,已经补全参数、修正占位符类型、补充键到表名的映射规则:
DO $$ DECLARE -- 配置键名到目标表名的映射关系 key_table_map jsonb := '{"firstt":"Table1", "secondt":"Table2"}'::jsonb; current_key text; target_tbl text; BEGIN FOR current_key IN SELECT jsonb_object_keys(key_table_map) LOOP target_tbl := key_table_map ->> current_key; EXECUTE format($dynsql$ INSERT INTO %I (id, sd, v) SELECT (json_populate_recordset(null::%I, json_array -> %L)).* FROM test $dynsql$, target_tbl, target_tbl, current_key); END LOOP; END $$;
注意事项
- 确保目标表字段名和JSON键名完全一致:id为integer类型、sd为varchar类型、v为varchar类型,你给出的表结构符合要求,不会出现类型转换错误
- 不要嵌套多层
json_array_elements拆分数组后再逐字段取值,json_populate_recordset本身就可以直接接收JSON数组参数批量转成行记录,写法更简洁性能更好
内容的提问来源于stack exchange,提问作者Kush
相关产品推荐
相关产品推荐

