MySQL Baumstruktur (Tree) selektieren (SELECT)

Updated . Posted . Visible to the public.

Oft möchte man eine Baumstruktur in einer MySQL-Tabelle selektieren.

+--------+-------------------+
| Parent | Child             |
+--------+-------------------+
| 1      | 2,3               |
|  2     | 4,5,6,7,8,9,10,11 |
|   6    | 12,13,14          |
|   8    | 15,16,17,18       |
|    12  | 19                |
|    14  | 20,21,22          |
|     19 | 23                |
+--------+-------------------+
DROP PROCEDURE IF EXISTS objsubtree;
DELIMITER go
CREATE PROCEDURE objsubtree( root char(18) )
BEGIN
  DROP TABLE IF EXISTS objsubtree;
  CREATE TABLE objsubtree ( ObjectUID char(18), ContainerUID char(18), level int,  Primary Key(ObjectUID,ContainerUID) ) ENGINE=MEMORY;
    SELECT ObjectUID, ContainerUID, 0 AS level
    FROM oms_link
    WHERE ContainerUID = root;
  REPEAT
    INSERT IGNORE INTO objsubtree
      SELECT f.ObjectUID, f.ContainerUID, s.level+1
      FROM oms_link AS f
      JOIN objsubtree AS s ON f.ContainerUID = s.ObjectUID;
  UNTIL Row_Count() = 0 END REPEAT;
  SELECT * FROM objsubtree;
  DROP TABLE IF EXISTS objsubtree;
END ;
go
DELIMITER ;
call objsubtree('101:12');  

Probier bitten nochfolgende Implementation aus:
Hierarchische Querys in MySQL Show archive.org snapshot

In MySQL 8.0 gibt es diesen neuen Rekursiven SELECT-Befehl:
Mysql Adjacency List Tree Show archive.org snapshot

Und das ist die Lösung

Alle Childs und Deep-Childs mit LevelNumber zurückgeben (ausgehend von 101:12)

WITH RECURSIVE link_path (ObjectUID, ContainerUID, LevelNumber) AS
(
  SELECT ObjectUID, ContainerUID, 0 LevelNumber
    FROM oms_link
    WHERE ContainerUID = '101:12'
  UNION ALL
  SELECT c.ObjectUID, c.ContainerUID, cp.LevelNumber + 1
    FROM link_path AS cp JOIN oms_link AS c
      ON cp.ObjectUID = c.ContainerUID
)
SELECT * FROM link_path
ORDER BY LevelNumber;

Und hier ein Beispiel, wie alle Parent-Elemente ausgehend von 101:12 zurückgegeben werden:

WITH RECURSIVE link_path (ObjectUID, ContainerUID, LevelNumber) AS
(
  SELECT ObjectUID, ContainerUID, 0 AS LevelNumber
    FROM oms_link
    WHERE ObjectUID = '301:1' -- child node
  UNION ALL
  SELECT c.ObjectUID, c.ContainerUID, cp.LevelNumber + 1
    FROM link_path AS cp JOIN oms_link AS c
      ON cp.ContainerUID = c.ObjectUID
)
SELECT * FROM link_path
GROUP BY ObjectUID, ContainerUID
ORDER BY LevelNumber
Stephan Blaurock
Last edit
Stephan Blaurock
Posted by Stephan Blaurock to Programming KB (2018-04-18 08:34)