[英]Extract attribute columns from hierarchical JSON dynamically - PostgreSQL
This query selects a hierarchical JSON as a table in PostgreSQL. The name of the columns could be hard code as done here, but that's not feasible when working with hundreds of columns.此查询选择分层结构 JSON 作为 PostgreSQL 中的表。列的名称可以是硬编码,但在处理数百列时这是不可行的。
JSON sample: 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"
}
]
}
]
}
Query sample:查询样本:
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
I want to get the same output of this code, but without hard coding:我想获得此代码的相同 output,但没有硬编码:
'SEQ' AS seq
'DESC_D' AS desc_d
'ID' AS id
'NODES' AS nodes
I need them dynamically written depending on the JSON我需要根据 JSON 动态编写它们
Found this solution but didn't work for me because my JSON is hierarchical (or maybe I didn't implement it the right way).找到了这个解决方案,但对我不起作用,因为我的 JSON 是分层的(或者我没有以正确的方式实现它)。
The proposed solution relies on a composite type which must be dynamically created with the following procedure:建议的解决方案依赖于必须使用以下过程动态创建的复合类型:
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 ;
$$ ;
First create the composite type:首先创建复合类型:
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) ;
And then the query:然后查询:
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
provides the expected result:提供预期的结果:
parent_id ![]() |
desc_d ![]() |
id ![]() |
nodes![]() |
seq![]() |
---|---|---|---|---|
null ![]() |
fam![]() |
2304500 ![]() |
[{"ID": "5214", "SEQ": "2.1", "NODES": [{"ID": "999", "SEQ": "3.1", "DESC_D": "test 1.1"}], "DESC_D": "test 1"}, {"ID": "74542", "SEQ": "2.2", "DESC_D": "test 2"}] ![]() |
1 ![]() |
2304500 ![]() |
test 1![]() |
5214 ![]() |
[{"ID": "999", "SEQ": "3.1", "DESC_D": "test 1.1"}] ![]() |
2.1 ![]() |
2304500 ![]() |
test 2![]() |
74542 ![]() |
null ![]() |
2.2 ![]() |
5214 ![]() |
test![]() |
1.1 ![]() |
999 ![]() |
null ![]() |
Note that in the query child
is broken down by CROSS JOIN LATERAL jsonb_each_text(child) AS v(key, value)
and then rebuild with jsonb_object_agg(lower(v.key), v.value)
so that v.key
are converted into lower cases and correspond to the attribute names of composite_type
which are necessarily in lower cases.请注意,在查询中,
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.