[英]Extract attribute columns from hierarchical JSON dynamically - PostgreSQL
此查询选择分层结构 JSON 作为 PostgreSQL 中的表。列的名称可以是硬编码,但在处理数百列时这是不可行的。
JSON 样本:
{
"NODES": [
{
"DESC_D": "fam",
"SEQ": "1",
"ID": "2304500",
"NODES": [
{
"DESC_D": "test 1",
"SEQ": "2.1",
"ID": "5214",
"NODES": [
{
"DESC_D": "test 1.1",
"SEQ": "3.1",
"ID": "999"
}
]
},
{
"DESC_D": "test 2",
"SEQ": "2.2",
"ID": "74542"
}
]
}
]
}
查询样本:
SELECT DISTINCT
child->>'SEQ' AS seq
, child->>'DESC_D' AS desc_d
, child->>'ID' AS id
, parent->>'ID' AS parent_id
, child->>'NODES' AS nodes
FROM jsonb_path_query('{"NODES":[{"DESC_D":"fam","SEQ":"1","ID":"2304500","NODES":[{"DESC_D":"test 1","SEQ":"2.1","ID":"5214","NODES":[{"DESC_D":"test 1.1","SEQ":"3.1","ID":"999"}]},{"DESC_D":"test 2","SEQ":"2.2","ID":"74542"}]}]}'
, '$.** ? (@.NODES.type() == "array")') AS parent
CROSS JOIN LATERAL jsonb_array_elements(parent->'NODES') AS child
ORDER BY seq
我想获得此代码的相同 output,但没有硬编码:
'SEQ' AS seq
'DESC_D' AS desc_d
'ID' AS id
'NODES' AS nodes
我需要根据 JSON 动态编写它们
找到了这个解决方案,但对我不起作用,因为我的 JSON 是分层的(或者我没有以正确的方式实现它)。
建议的解决方案依赖于必须使用以下过程动态创建的复合类型:
CREATE OR REPLACE PROCEDURE composite_type (j jsonb) LANGUAGE plpgsql AS
$$
DECLARE
_columns text ;
BEGIN
SELECT string_agg(DISTINCT v.key || ' text', ',')
INTO _columns
FROM jsonb_path_query( j
, '$.** ? (@.NODES.type() == "array")') AS parent
CROSS JOIN LATERAL jsonb_array_elements(parent->'NODES') AS child
CROSS JOIN LATERAL jsonb_each_text(child) AS v(key, value) ;
DROP TYPE IF EXISTS composite_type ;
EXECUTE 'CREATE TYPE composite_type AS (' || _columns || ')' ;
END ;
$$ ;
首先创建复合类型:
CALL composite_type ('{"NODES":[{"DESC_D":"fam","SEQ":"1","ID":"2304500","NODES":[{"DESC_D":"test 1","SEQ":"2.1","ID":"5214","NODES":[{"DESC_D":"test 1.1","SEQ":"3.1","ID":"999"}]},{"DESC_D":"test 2","SEQ":"2.2","ID":"74542"}]}]}' :: jsonb) ;
然后查询:
SELECT parent->>'ID' AS parent_id
, (jsonb_populate_record(null :: composite_type, jsonb_object_agg(lower(v.key), v.value))).*
FROM jsonb_path_query('{"NODES":[{"DESC_D":"fam","SEQ":"1","ID":"2304500","NODES":[{"DESC_D":"test 1","SEQ":"2.1","ID":"5214","NODES":[{"DESC_D":"test 1.1","SEQ":"3.1","ID":"999"}]},{"DESC_D":"test 2","SEQ":"2.2","ID":"74542"}]}]}'
, '$.** ? (@.NODES.type() == "array")') AS parent
CROSS JOIN LATERAL jsonb_array_elements(parent->'NODES') AS child
CROSS JOIN LATERAL jsonb_each_text(child) AS v(key, value)
GROUP BY parent, child
ORDER BY seq
提供预期的结果:
parent_id | desc_d | ID | 节点 | 序号 |
---|---|---|---|---|
null | 秘境 | 2304500 | [{“ID”:“5214”,“SEQ”:“2.1”,“节点”:[{“ID”:“999”,“SEQ”:“3.1”,“DESC_D”:“测试 1.1”}] , "DESC_D": "test 1"}, {"ID": "74542", "SEQ": "2.2", "DESC_D": "test 2"}] | 1个 |
2304500 | 测试 1 | 5214 | [{“ID”:“999”,“SEQ”:“3.1”,“DESC_D”:“测试 1.1”}] | 2.1 |
2304500 | 测试 2 | 74542 | null | 2.2 |
5214 | 测试 | 1.1 | 999 | null |
请注意,在查询中, child
被CROSS JOIN LATERAL jsonb_each_text(child) AS v(key, value)
分解,然后使用jsonb_object_agg(lower(v.key), v.value)
进行重建,以便v.key
转换为较低的cases 并对应于composite_type
的属性名称,这些名称必须是小写的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.