我本来希望以下查询返回所有带有各自子代的人。
WITH RECURSIVE nested_people (id, name, children) AS ( SELECT id, name, NULL::JSON AS children FROM people WHERE parent_id IS NULL UNION ALL SELECT people.id, people.name, ROW_TO_JSON(nested_people.*) AS children FROM people JOIN nested_people ON people.parent_id = nested_people.id ) SELECT * FROM nested_people;
但是实际上,它的确是相反的。我想不出无需额外的CTE就能进行正确嵌套的方法。有办法吗?
示例数据
+----+-------+-----------+ | id | name | parent_id | +----+-------+-----------+ | 1 | Adam | null | | 2 | Abel | 1 | | 3 | Cain | 1 | | 4 | Enoch | 3 | +----+-------+-----------+
结果
+----+-------+--------------------------------------------------------------------------+ | id | name | children | +----+-------+--------------------------------------------------------------------------+ | 1 | Adam | null | | 2 | Abel | {"id":1,"name":"Adam","children":null} | | 3 | Cain | {"id":1,"name":"Adam","children":null} | | 4 | Enoch | {"id":3,"name":"Cain","children":{"id":1,"name":"Adam","children":null}} | +----+-------+--------------------------------------------------------------------------+
预期结果
+----+-------+----------------------------------------------------------------------------------------------------------------------+ | id | name | children | +----+-------+----------------------------------------------------------------------------------------------------------------------+ | 1 | Adam | [{"id":2, "name":"Abel", "children":null},{"id":3,"name":"Cain","children":[{"id":4,"name":"Enoch","children":null}] | | 2 | Abel | null | | 3 | Cain | [{"id":4,"name":"Enoch","children":null}] | | 4 | Enoch | null | +----+-------+----------------------------------------------------------------------------------------------------------------------+
该rCTE从另一侧遍历树:
WITH RECURSIVE cte AS ( SELECT id, parent_id, name, NULL::JSON AS children FROM people p WHERE NOT EXISTS ( -- only leaf nodes; see link below SELECT 1 FROM people WHERE parent_id = p.id ) UNION ALL SELECT p.id, p.parent_id, p.name, row_to_json(c) AS children FROM cte c JOIN people p ON p.id = c.parent_id ) SELECT id, name, json_agg(children) AS children FROM cte GROUP BY 1, 2;
SQL提琴。
使用json_agg()到每个节点聚集多个分支外SELECT。 与您期望的结果之间的微小差异:
json_agg()
SELECT
parent_id
children
都可以进行调整,但是我希望结果对您来说是可以的。