sql - 使用 PostgreSQL10 根据行中的值分层聚合 JSON

标签 sql json postgresql

我有一个 PostgreSQL 10 表,它充当“字典”,其结构如下:

<表类=“s-表”> <标题> 键 值 <正文> style_selection_color style_selection_weight style_line_color style_line_weight ...

现在我想知道是否有一种方法可以使用表中的值构建 JSON,并根据“key”的值构建层次结构? 像这样的东西:

style --> selection --> colorstyle --> line --> color

以 JSON 结束:

{
  style: [
    selection: {
      color: "...",
      weight: "..."
    },
    line: {
      color: "...",
      weight: "..."
    }
  ]
}

这样的壮举可以实现吗?如果是这样,我该怎么办?

是否可以这样做,以便无论我的表中有什么键,它总是返回正确构建的 JSON?

提前致谢

最佳答案

PosGres 10 及更高版本的工作解决方案

我向您建议一个通用解决方案,将key数据转换为text[]类型,以便它可以用作jsonpath内部标准 jsonb_set() 函数。

但是当我们迭代 jsonb_set() 函数时,我们首先需要创建一个与该函数关联的 aggregate 函数:

CREATE AGGREGATE jsonb_set_agg(p text[], z jsonb, b boolean)
( sfunc = jsonb_set
, stype = jsonb
, initcond = '{}'
)

然后,我们将 key 数据转换为 text[],并自动生成 jsonpath 列表,该列表将允许逐步迭代构建最终的 jsonb 数据:

 SELECT i.id
      , max(i.id) OVER (PARTITION BY t.key) AS id_max
      , p.path[1 : i.id] AS jsonbpath
      , to_jsonb(t.value) AS value
   FROM mytable AS t
  CROSS JOIN LATERAL string_to_array(t.key, '_') AS p(path)
  CROSS JOIN LATERAL generate_series(1, array_length(p.path, 1)) AS i(id)

最终查询如下所示:

WITH list AS
( SELECT i.id
       , max(i.id) OVER (PARTITION BY t.key) AS id_max
       , p.path[1 : i.id] AS jsonpath
       , to_jsonb(t.value) AS value
   FROM mytable AS t
  CROSS JOIN LATERAL string_to_array(t.key, '_') AS p(path)
  CROSS JOIN LATERAL generate_series(1, array_length(p.path, 1)) AS i(id)
)
SELECT jsonb_set_agg( l.jsonpath
                    , CASE 
                        WHEN l.id = l.id_max THEN l.value
                        ELSE '{}' :: jsonb
                      END
                    , true 
                    ORDER BY l.id
                    )
  FROM list AS l

结果与您的预期略有不同(顶级 json 数组被 json 对象替换),但对我来说听起来更有逻辑:

{"style": {"line": {"color": "C"
                   , "weight": "D"
                   }
          , "selection": {"color": "A"
                         , "weight": "B"
                         }
          }
}

完整测试结果在 dbfiddle .

关于sql - 使用 PostgreSQL10 根据行中的值分层聚合 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70894367/

相关文章:

mysql - 选择 JSON 文件并将其插入 SQL Server 表中

ruby-on-rails - 如何在 rails (postgres) 查询中参数化日期范围?

postgresql - 在文本文件中记录 PostgreSQL session

sql - PSQL 将 jsonb 属性更新为当前值

php - SQL值必须大于其他值达到一个值

sql - 在 ORDER BY 中使用带有别名列的计算

mysql - 从多个表中获取多个值

sql - 使用 SQL LAG 函数计算股票 yield

javascript - 如何将表单字段的值设置为 JSON 中的值?

ios - 带有嵌套 JSON 的 valueForKeyPath