给定一个包含未知树结构的路径/节点的表:
| id | path_id | node
| 1 | p1 | n1
| 2 | p1 | n2
| 3 | p1 | n3
| 4 | p2 | n1
| 5 | p2 | n2
| 6 | p2 | n4
对应的树结构为:
n1
/
n2
/ \
n3 n4
是否可以使用 SQL 和 PostgreSQL 函数为该树生成 JSON 对象?
看起来你有一个路径列表,其中部分重叠。
使用
jsonb
和 jsonb_object_agg()
,产生更密集的结果,其中每条边都是一个键/值对。
jsonb
开箱即用地删除重复的键值。不需要DISTINCT
:
SELECT jsonb_object_agg(node, parent) AS edges
FROM (
SELECT node, lag(node) OVER (PARTITION BY path_id ORDER BY id) AS parent
FROM tbl
ORDER BY parent NULLS FIRST, node -- ORDER BY optional
) sub;
jsonb_object_agg_strict()
还可以删除具有空值的对象,有效地修剪根部的悬垂边缘:
SELECT jsonb_object_agg_strict(node, parent) AS edges
FROM (
-- same as above
) sub;
旧版
json
解决方案。首先删除重复的边缘,因为 json
保留所有对象,甚至重复的键。
SELECT DISTINCT
node, lag(node) OVER (PARTITION BY path_id ORDER BY id) AS parent
FROM tbl
ORDER BY parent NULLS FIRST, node; -- ORDER BY optional
对于根节点,parent
为 NULL。您可能想从结果中删除这个“非边缘”。json_agg()
:
SELECT json_agg(sub) AS edges
FROM (
SELECT DISTINCT
node, lag(node) OVER (PARTITION BY path_id ORDER BY id) AS parent
FROM tbl
ORDER BY parent NULLS FIRST, node -- ORDER BY optional
) sub;