代码之家  ›  专栏  ›  技术社区  ›  Dennis

获取mysql中所有父节点的任何节点的父/子关系的完整树

  •  0
  • Dennis  · 技术社区  · 5 年前

    示例数据:

    +----+-------+----------+
    | org_id | Name  | ParentID |
    +----+-------+----------+
    |  1 | Org1  | 2        |
    |  2 | Org2  | NULL     |
    |  3 | Org3  | 5        |
    |  5 | Org5  | 1        |
    | 14 | Org14 | 1        |
    +----+-------+----------+
    

    如果我以用户身份登录,用户名为org_id 1(Org1)。我想检索该用户的完整树。

    我有以下递归查询:

    WITH RECURSIVE cte (org_id, name, parent_id) AS (
         SELECT org_id, name, parent_id
         FROM organization
         WHERE org_id = 1
         UNION ALL
         SELECT t1.org_id, t1.name, t1.parent_id
         FROM organization t1
         INNER JOIN cte t2 ON t1.parent_id = t2.org_id
    )
    SELECT * FROM cte;
    

    但是,此查询只给了我当前id的子项(在本例中为Org1)。我如何将所有父节点也包含在结果集中,以便准确重建整棵树?

    编辑:我使用的是MariaDB 10.4.10版本

    编辑: 我尝试了以下答案中的查询,但遇到了语法错误: syntax error

    0 回复  |  直到 5 年前
        1
  •  1
  •   slaakso    5 年前

    你有一个CTE来照顾孩子。为什么不使用另一个去相反的方向,得到父母:

    MySQL:

    (WITH RECURSIVE cte (id, name, parent_id) AS (
         SELECT id, name, parent_id
         FROM organization
         WHERE id = 1
         UNION  
         SELECT t1.id, t1.name, t1.parent_id
         FROM organization t1
           INNER JOIN cte t2 ON t1.parent_id = t2.id 
    )
    SELECT * FROM cte)
    UNION
    (WITH RECURSIVE cte (id, name, parent_id) AS (
         SELECT id, name, parent_id
         FROM organization
         WHERE id = 1
         UNION 
         SELECT t1.id, t1.name, t1.parent_id
         FROM organization t1
           INNER JOIN cte t2 ON t2.parent_id = t1.id 
    )
    SELECT * FROM cte)
    

    同时支持MySQL和MariaDB的版本:

    MySQL/MariaDB:

    WITH RECURSIVE cte (id, name, parent_id, dir) AS (
         SELECT id, name, parent_id, cast(null as char(10)) as dir
         FROM organization
         WHERE id = 1
         UNION  
         SELECT t1.id, t1.name, t1.parent_id, ifnull(t2.dir, 'down')
         FROM organization t1
           INNER JOIN cte t2 ON t1.parent_id = t2.id and ifnull(t2.dir, 'down')='down'
         UNION
         SELECT t1.id, t1.name, t1.parent_id, ifnull(t2.dir, 'up')
         FROM organization t1
           INNER JOIN cte t2 ON t2.parent_id = t1.id and ifnull(t2.dir, 'up')='up'
    )
    SELECT id, name, parent_id FROM cte;
    

    请参阅 db-fiddle dbfiddle