从 Postgres 和 jOOQ 中的分层表递归生成 JSON 树
Posted
技术标签:
【中文标题】从 Postgres 和 jOOQ 中的分层表递归生成 JSON 树【英文标题】:Recursively generate JSON tree from hierarchical table in Postgres and jOOQ 【发布时间】:2021-06-13 18:47:13 【问题描述】:我在 Postgres 数据库中有一个分层表,例如category
。结构简单如下:
id | parent_id | name |
---|---|---|
1 | null | A |
2 | null | B |
3 | 1 | A1 |
4 | 3 | A1a |
5 | 3 | A1b |
6 | 2 | B1 |
7 | 2 | B2 |
我需要从这张表中得到这样的递归深度树结构:
[
"id": 1,
"name": "A",
"children": [
"id": 3,
"name": "A1",
"children": [
"id": 4,
"name": "A1a",
"children": []
,
"id": 5,
"name": "A1b",
"children": []
]
]
,
"id": 2,
"name": "B",
"children": [
"id": 6,
"name": "B1",
"children": []
,
"id": 7,
"name": "B2",
"children": []
]
,
]
是否有可能使用WITH RECURSIVE
和json_build_array()
的组合或其他一些解决方案的未知深度?
【问题讨论】:
【参考方案1】:我在this excellent blog post here 中找到了这个问题的答案,因为我想知道如何在 jOOQ 中概括这个问题。如果 jOOQ 可以以通用方式实现任意递归对象树,那将很有用:https://github.com/jOOQ/jOOQ/issues/12341
同时,使用受上述博客文章启发的 SQL 语句,并进行了一些修改。如果必须,请转换为 jOOQ,尽管您也可以将其存储为视图:
WITH RECURSIVE
d1 (id, parent_id, name) as (
values
(1, null, 'A'),
(2, null, 'B'),
(3, 1, 'A1'),
(4, 3, 'A1a'),
(5, 3, 'A1b'),
(6, 2, 'B1'),
(7, 2, 'B2')
),
d2 AS (
SELECT d1.*, 0 AS level
FROM d1
WHERE parent_id IS NULL
UNION ALL
SELECT d1.*, d2.level + 1
FROM d1
JOIN d2 ON d2.id = d1.parent_id
),
d3 AS (
SELECT d2.*, jsonb_build_array() children
FROM d2
WHERE level = (SELECT max(level) FROM d2)
UNION (
SELECT (branch_parent).*, jsonb_agg(branch_child)
FROM (
SELECT
branch_parent,
to_jsonb(branch_child) - 'level' - 'parent_id' AS branch_child
FROM d2 branch_parent
JOIN d3 branch_child ON branch_child.parent_id = branch_parent.id
) branch
GROUP BY branch.branch_parent
UNION
SELECT d2.*, jsonb_build_array()
FROM d2
WHERE d2.id NOT IN (
SELECT parent_id FROM d2 WHERE parent_id IS NOT NULL
)
)
)
SELECT jsonb_pretty(jsonb_agg(to_jsonb(d3) - 'level' - 'parent_id')) AS tree
FROM d3
WHERE level = 0;
dbfiddle。再次阅读linked blog post,了解其工作原理
【讨论】:
以上是关于从 Postgres 和 jOOQ 中的分层表递归生成 JSON 树的主要内容,如果未能解决你的问题,请参考以下文章
从jOOQ访问名为CHECK CONSTRAINTS的Postgres
JOOQ 强制类型将 BigInteger 转换为 BigDecimal 以用于 POSTGRES
将 JooQ 与 SQL Server 一起使用,getTables() 方法返回服务器上所有数据库中的所有表