Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL:So finden Sie Blätter in einem bestimmten Knoten

Es gibt keine Möglichkeit, dies in einer einzigen Abfrage zu tun. Selbst wenn, wäre es wahrscheinlich sehr ineffizient.

Wir können dies mit einer gespeicherten Prozedur und einer Schleife tun. Mit den von Ihnen hinzugefügten Indizes sollte es auch ziemlich schnell gehen. Dies verwendet zwei Tabellen, die die Knoten aus der Eingabetabelle (A) auswählen und den Knoten und ihre Kinder in (B) einfügen. Es tauscht dann B gegen A und wiederholt es, bis in A keine Nicht-Blattknoten mehr existieren. Das Schöne ist, dass es nur so viele Schleifeniterationen gibt, wie es Ebenen zwischen dem Eingabeknoten und dem letzten Blattknoten gibt, was in den meisten Fällen der Fall ist wahrscheinlich nicht so tief. Diese gespeicherte Prozedur wäre schneller, als sie extern im Code auszuführen.

FYI Ich hatte Schwierigkeiten mit meiner Installation beim Umgang mit temporären Tabellen. Wenn Sie einen „Fehler 2“ erhalten, entfernen Sie das Schlüsselwort „temporary“.

delimiter $$
drop procedure if exists GetLeafNodes $$
create procedure GetLeafNodes(nodeid int)
begin
declare N int default 1;

-- create two working sets of IDs, we'll go back and forth between these two sets
drop temporary table if exists A;
drop temporary table if exists B;
create temporary table A(node int, child int);
create temporary table B(node int, child int);

-- insert our single input node into the working set
insert into A values (null, nodeid);

while (N>0) do
  -- keep selecting child nodes for each node we are now tracking
  -- leaf nodes will end up with the child set to null
  insert into B
  select ifnull(A.child,A.node), tree.ID
    from A
    left outer join DATA_TREE as tree on A.child=tree.parent_id;

  -- now swap A and B
  rename table A to temp, B to A, temp to B;

  -- remove non-leaf nodes from table B
  delete from B;

  -- exit when there are no longer any non-leaf nodes in A
  set N=(select count(*) from A where child is not null);
end while;

-- now output our list of leaf nodes
select node from A;

drop temporary table A;
drop temporary table B;
end $$
DELIMITER ;
call GetLeafNodes(4);

Ich habe den folgenden Beispielsatz zum Testen verwendet:

CREATE TABLE `DATA_TREE` (
  `ID` int(11) NOT NULL,
  `PARENT_ID` int(11) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `ID_UNIQUE` (`ID`),
  KEY `fk_DATA_TREE_1_idx` (`PARENT_ID`)
) ENGINE=InnoDB
;

insert into DATA_TREE values
(1,0),(2,1),(3,1),(4,1),(5,3),(6,3),(7,4),(8,4),(9,4),(10,6),(11,6),(12,7),(13,9),(14,9),(15,12),(16,12),(17,12),(18,14);