sqlrecursiontreemariadbmariadb-10.3

Get full tree of parent/child relationships in mysql of any node in the tree with all parents


Example data:

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

If I am logged in as user with org_id 1 (Org1). I want to retrieve the full tree of that user.

I have the following recursive Query :

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;

However, this query only gives me the children of the current id (Org1 in this example). How can I include all the parents as well in the result set, so I can rebuild the entire tree accurately?

EDIT: I am using MariaDB version 10.4.10

EDIT: I tried the query as in the answer below, i'm getting a syntax error : syntax error


Solution

  • You have a CTE that gets the children. Why not use another to go to opposite direction and get the parents:

    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)
    

    And a version which works both in MySQL and 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;
    

    See db-fiddle and dbfiddle