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

如何利用PostgreSQL带点符号列生成嵌套JSON(B)结果?

利用列名的点符号自动构建嵌套JSONB(PostgreSQL)

当然可以简化操作,不用手动嵌套jsonb_build_object。下面提供两种实用方法,自动解析列名中的点分隔层级,生成目标嵌套JSONB结构:

方法1:用递归CTE+聚合函数实现(无需自定义函数)

适合临时查询,不需要创建额外对象。假设你的表名为flat_table,包含id、title.en、title.fr、category.name.en这些列:

WITH recursive column_hierarchy AS (
  -- 把每行转成JSONB,拆分出所有列名和对应值,并将列名按点拆分为路径数组
  SELECT
    id,
    regexp_split_to_array(column_name, '\.') AS path,
    column_value
  FROM
    flat_table,
    jsonb_each_text(to_jsonb(flat_table) - 'id') AS j(column_name, column_value)
),
nested_json AS (
  -- 从最底层的键值对开始构建
  SELECT
    id,
    path[array_length(path, 1)] AS key,
    path[1:array_length(path, 1)-1] AS parent_path,
    to_jsonb(column_value) AS value
  FROM column_hierarchy
  WHERE array_length(path, 1) = 1
  UNION ALL
  -- 递归向上合并层级,把底层JSON嵌套到父层级中
  SELECT
    nh.id,
    ch.path[array_length(ch.path, 1)] AS key,
    ch.path[1:array_length(ch.path, 1)-1] AS parent_path,
    jsonb_build_object(ch.path[array_length(ch.path, 1)], nh.value) AS value
  FROM nested_json nh
  JOIN column_hierarchy ch ON
    nh.id = ch.id AND
    nh.parent_path = ch.path[1:array_length(ch.path, 1)-1]
)
-- 聚合每个id对应的所有层级,生成最终嵌套JSONB
SELECT
  id,
  (SELECT jsonb_object_agg(key, value) FROM nested_json WHERE id = ft.id) AS nested_json
FROM flat_table ft
GROUP BY id;

方法2:创建自定义PL/pgSQL函数(适合重复使用)

如果需要频繁执行这类转换,写一个自定义函数会更简洁:

CREATE OR REPLACE FUNCTION build_nested_jsonb(p_row jsonb) RETURNS jsonb AS $$
DECLARE
  result jsonb := '{}'::jsonb;
  key text;
  value jsonb;
  path text[];
BEGIN
  -- 遍历行转成的JSONB中的每个键值对
  FOR key, value IN SELECT * FROM jsonb_each(p_row) LOOP
    -- 将列名按点拆分为嵌套路径数组
    path := regexp_split_to_array(key, '\.');
    -- 把值插入到对应的嵌套路径位置
    result := jsonb_set(result, path, value, true);
  END LOOP;
  RETURN result;
END;
$$ LANGUAGE plpgsql;

使用时只需一行SQL:

SELECT id, build_nested_jsonb(to_jsonb(flat_table) - 'id') AS nested_json
FROM flat_table;

对比手动嵌套的优势

手动写法需要硬编码每个层级的jsonb_build_object,比如:

SELECT
  id,
  jsonb_build_object(
    'title', jsonb_build_object(
      'en', "title.en",
      'fr', "title.fr"
    ),
    'category', jsonb_build_object(
      'name', jsonb_build_object(
        'en', "category.name.en"
      )
    )
  ) AS nested_json
FROM flat_table;

当列数量多、层级深时,手动写法不仅繁琐,还容易出错。上面两种方法能自动解析列名的层级结构,大幅减少重复代码。

注意事项

  • 确保列名中的点是严格的层级分隔符,不要包含需要保留的点(如果有,需要先转义再处理)
  • 若存在重复的路径(比如两个列对应同一个嵌套键),jsonb_set会覆盖已有值,需保证列名的唯一性

内容的提问来源于stack exchange,提问作者behnam-io

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:20:41