Obtener este resultado recursivamente es complicado (aunque posible). Sin embargo, normalmente no es muy eficiente y hay mucho mejor manera de resolver este problema.
Básicamente, aumenta la tabla con una columna adicional que rastrea el árbol hasta la parte superior; lo llamaré "Upchain". Es solo una cadena larga que se parece a esto:
name | id | parent_id | upchain
root1 | 1 | NULL | 1:
root2 | 2 | NULL | 2:
root1sub1 | 3 | 1 | 1:3:
root1sub2 | 4 | 1 | 1:4:
root2sub1 | 5 | 2 | 2:5:
root2sub2 | 6 | 2 | 2:6:
root1sub1sub1 | 7 | 3 | 1:3:7:
Es muy fácil mantener actualizado este campo usando un activador en la tabla. (Disculpas por la terminología, pero siempre he hecho esto con SQL Server). Cada vez que agrega o elimina un registro, o actualiza el campo parent_id, solo necesita actualizar el campo upchain en esa parte del árbol. Ese es un trabajo trivial porque simplemente toma la cadena ascendente del registro principal y agrega la identificación del registro actual. Todos los registros secundarios se identifican fácilmente usando LIKE para buscar registros con la cadena inicial en su cadena ascendente.
Lo que está haciendo de manera efectiva es cambiar un poco de actividad de escritura adicional por un gran guardando cuando vengas a leer los datos.
Cuando desea seleccionar una rama completa en el árbol, es trivial. Suponga que desea la rama debajo del nodo 1. El nodo 1 tiene una cadena ascendente '1:', por lo que sabe que cualquier nodo en la rama del árbol debajo de ese nodo debe tener una cadena ascendente que comience con '1:...'. Así que solo haz esto:
SELECT *
FROM table
WHERE upchain LIKE '1:%'
Esto es extremadamente rápido (indexar el campo upchain, por supuesto). Como beneficio adicional, también hace que muchas actividades sean extremadamente simples, como encontrar árboles parciales, nivel dentro del árbol, etc.
Lo he usado en aplicaciones que rastrean grandes jerarquías de informes de empleados, pero puede usarlo para prácticamente cualquier estructura de árbol (desglose de partes, etc.)
Notas (para cualquier persona interesada):
- No he explicado paso a paso el código SQL, pero una vez que obtiene el principio, es bastante simple de implementar. No soy un gran programador, así que hablo por experiencia.
- Si ya tiene datos en la tabla, debe hacer una actualización única para sincronizar las cadenas ascendentes inicialmente. Nuevamente, esto no es difícil ya que el código es muy similar al código de ACTUALIZACIÓN en los activadores.
- Esta técnica también es una buena manera de identificar referencias circulares que, de otro modo, pueden ser difíciles de detectar.