sql >> Base de Datos >  >> RDS >> Mysql

MySQL:cómo encontrar hojas en un nodo específico

No hay manera de hacer esto en una sola consulta. Incluso si lo hubiera, probablemente sería muy ineficiente.

Podemos hacerlo con un procedimiento almacenado y un bucle. Con los índices que agregó, también debería ser bastante rápido. Esto usa dos tablas seleccionando los nodos de la tabla de entrada (A) e insertando el nodo y sus hijos en (B). Luego cambia B por A y repite hasta que no existen más nodos que no sean hoja en A. Lo bueno es que las iteraciones de bucle solo serían tantas como niveles haya entre el nodo de entrada y el último nodo hoja, que en la mayoría de los casos es probablemente no tan profundo. Este procedimiento almacenado sería más rápido que hacerlo externamente en código.

Para su información, tuve dificultades con mi instalación para manejar tablas temporales, si recibe un 'error 2', elimine la palabra clave temporal.

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

Usé el siguiente conjunto de muestra para la prueba:

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