1

我有一个名为 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 以按照我的意愿合并值的任何建议?一直在玩这个,但没有任何运气。

谢谢!

4

0 回答 0