我有一个名为 scope 的自引用表(在我的 user_account 架构中),它是分层数据 - 一些示例数据(Postgres 9.4):
*****编辑:******
制作了一个 SQL 小提琴:http ://sqlfiddle.com/#!15/43ff9/2/0有一个更详细的例子。请注意 JSON 输出底层的重复性质。我将把这些信息留在这里以供参考。
*****结束编辑******
user_account.scope
id name parent_id
1 user NULL
2 user:create 1
3 user:delete 1
4 user:modify 1
5 user:modify:all 4
6 user:modify:some 4
7 user:modify:ex 4
显然,顶级作用域没有 parent_id,它可以(任意)深入多个级别。
我正在尝试编写一个 SQL 查询,它将整个表作为嵌套的 JSON 对象递归返回。我在这方面取得了很大的成功:
WITH json_agg_scope_cte AS (
WITH scope_cte AS (
WITH RECURSIVE sub_scopes_cte AS (
SELECT
s.*,
NULL :: JSON AS sub_scopes
FROM
user_account.scope s
WHERE NOT EXISTS(
SELECT 1
FROM user_account.scope
WHERE parent_id = s.id
)
AND s.deleted = FALSE
UNION ALL
SELECT
s.*,
row_to_json(ssc) AS sub_scopes
FROM
sub_scopes_cte ssc
JOIN user_account.scope s
ON s.id = ssc.parent_id
AND s.deleted = FALSE
)
SELECT
id,
scope,
json_agg(sub_scopes) AS sub_scopes
FROM sub_scopes_cte ssc
WHERE parent_id IS NULL
GROUP BY 1, 2
)
SELECT
s.*,
sc.sub_scopes
FROM user_account.scope s
INNER JOIN scope_cte sc
ON s.id = sc.id
)
SELECT json_agg(json_agg_scope_cte.*) AS scopes
FROM json_agg_scope_cte
但问题是,子范围被列为顶级项目的数组(因为 json_agg(sub_scopes) 部分),但仅列为简单的 NULL 或任何嵌套的单个对象(因为 row_to_json( ssc)部分)。它还在 JSON 中重复父级,为其每个 sub_scopes 重复一次。
我得到了什么:
"scopes":
[{
"scope": "top_scope"
"sub_scopes":
[{
"scope": "mid_scope"
"sub_scopes": // NOT an array, needs to be
{
"scope": "bottom_scope_1"
"sub_scopes": NULL // Should be an array with NULL in it, consistent with format of others
}
},
{
"scope": "mid_scope" // repeated, bad
"sub_scopes":
{
"scope": "bottom_scope_2"
"sub_scopes": NULL
}
}]
}]
我想要的是:
"scopes":
[{
"scope": "top_scope"
"sub_scopes":
[{
"scope": "mid_scope"
"sub_scopes": // array
[{
"scope": "bottom_scope_1"
"sub_scopes": [NULL] // array as well!
},
{
"scope": "bottom_scope_2"
"sub_scopes": [NULL]
}]
}]
}]
我尝试将 row_to_json 更改为 json_agg,但您不能在递归调用中使用聚合函数。关于如何 A)修复此查询或 B)postgres 方法来“修复”json 以按照我的意愿合并值的任何建议?一直在玩这个,但没有任何运气。
谢谢!