[英]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.