階層データである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がなく、複数のレベル(任意)に深くなる可能性があります。
テーブル全体をネストされた JSON オブジェクトとして再帰的に返す SQL クエリを作成しようとしています。私はこれでほとんど成功しました:
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) 部分)。また、サブスコープごとに 1 回ずつ、JSON 内で親を繰り返します。
私が得ているもの:
"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) json を "修正" して、必要に応じて値をマージする postgres の方法に関する提案はありますか? これで永遠に遊んでいますが、運がありません。
ありがとう!