Получить полное дерево родительских / дочерних отношений в mysql любого узла в дереве со всеми родителями - PullRequest
1 голос
/ 01 февраля 2020

Пример данных:

+----+-------+----------+
| 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;

Однако этот запрос дает мне только потомков текущего идентификатора (в данном примере Org1). Как я могу включить всех родителей в набор результатов, чтобы я мог точно перестроить все дерево?

РЕДАКТИРОВАТЬ: я использую MariaDB версии 10.4.10

РЕДАКТИРОВАТЬ: я пробовал запрос, как в ответе ниже, я получаю синтаксическую ошибку: syntax error

1 Ответ

1 голос
/ 01 февраля 2020

У вас есть CTE, который получает детей. Почему бы не использовать другой для go в противоположном направлении и получить родителей:

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

...