Tengo una tabla MySQL que es la siguiente:
id | name | parent_id
19 | category1 | 0
20 | category2 | 19
21 | category3 | 20
22 | category4 | 21
......
Ahora, quiero tener una única consulta MySQL a la que simplemente proporcione la identificación [por ejemplo, decir 'id = 19'], entonces debería obtener todos sus identificadores secundarios [es decir, el resultado debería tener identificadores '20, 21,22 ']. ... Además, no se conoce la jerarquía de los hijos, puede variar ...
Además, ya tengo la solución usando el bucle for ..... Si es posible, avíseme cómo lograrlo usando una sola consulta MySQL.
mysql
sql
hierarchical-data
recursive-query
Tarun Parswani
fuente
fuente
Respuestas:
Para MySQL 8+: use la
with
sintaxis recursiva .Para MySQL 5.x: use variables en línea, ID de ruta o autouniones.
MySQL 8+
El valor especificado en
parent_id = 19
debe establecerse en elid
del padre del que desea seleccionar todos los descendientes.MySQL 5.x
Para las versiones de MySQL que no admiten expresiones de tabla comunes (hasta la versión 5.7), lo lograría con la siguiente consulta:
Aquí hay un violín .
Aquí, el valor especificado en
@pv := '19'
debe establecerse en elid
del padre del que desea seleccionar todos los descendientes.Esto funcionará también si un padre tiene varios hijos. Sin embargo, se requiere que cada registro cumpla la condición
parent_id < id
, de lo contrario los resultados no serán completos.Asignaciones variables dentro de una consulta
Esta consulta utiliza una sintaxis específica de MySQL: las variables se asignan y modifican durante su ejecución. Se hacen algunas suposiciones sobre el orden de ejecución:
from
cláusula se evalúa primero. Entonces ahí es donde@pv
se inicializa.where
cláusula se evalúa para cada registro en el orden de recuperación de losfrom
alias. Entonces, aquí es donde se establece una condición para incluir solo registros para los cuales el padre ya se identificó como parte del árbol descendente (todos los descendientes del padre primario se agregan progresivamente@pv
).where
cláusula se evalúan en orden, y la evaluación se interrumpe una vez que el resultado total es seguro. Por lo tanto, la segunda condición debe estar en segundo lugar, ya que agrega laid
a la lista principal, y esto solo debería suceder siid
pasa la primera condición. Lalength
función sólo se llama para asegurarse de que esta condición se cumple siempre, incluso si lapv
cadena sería por alguna razón producir un valor Falsy.En general, uno puede encontrar estas suposiciones demasiado arriesgadas para confiar en ellas. La documentación advierte:
Entonces, aunque funciona de manera consistente con la consulta anterior, el orden de evaluación puede cambiar, por ejemplo, cuando agrega condiciones o utiliza esta consulta como una vista o subconsulta en una consulta más grande. Es una "característica" que se eliminará en una futura versión de MySQL :
Como se indicó anteriormente, desde MySQL 8.0 en adelante, debe usar la
with
sintaxis recursiva .Eficiencia
Para conjuntos de datos muy grandes, esta solución puede ser lenta, ya que la
find_in_set
operación no es la forma más ideal de encontrar un número en una lista, ciertamente no en una lista que alcanza un tamaño en el mismo orden de magnitud que el número de registros devueltos.Alternativa 1:
with recursive
,connect by
Cada vez más bases de datos implementan la sintaxis estándar SQL: 1999 ISO
WITH [RECURSIVE]
para consultas recursivas (por ejemplo, Postgres 8.4+ , SQL Server 2005+ , DB2 , Oracle 11gR2 + , SQLite 3.8.4+ , Firebird 2.1+ , H2 , HyperSQL 2.1.0+ , Teradata , MariaDB 10.2.2+ ). Y a partir de la versión 8.0, también MySQL lo admite . Consulte la parte superior de esta respuesta para conocer la sintaxis que debe usar.Algunas bases de datos tienen una sintaxis alternativa no estándar para búsquedas jerárquicas, como la
CONNECT BY
cláusula disponible en Oracle , DB2 , Informix , CUBRID y otras bases de datos.MySQL versión 5.7 no ofrece tal característica. Cuando su motor de base de datos proporciona esta sintaxis o puede migrar a una que sí lo haga, entonces esa es ciertamente la mejor opción. Si no, entonces también considere las siguientes alternativas.
Alternativa 2: identificadores de estilo de ruta
Las cosas se vuelven mucho más fáciles si asigna
id
valores que contienen la información jerárquica: una ruta. Por ejemplo, en su caso esto podría verse así:Entonces tu
select
se vería así:Alternativa 3: autouniones repetidas
Si conoce un límite superior de cuán profundo puede llegar a ser su árbol de jerarquía, puede usar una
sql
consulta estándar como esta:Ver este violín
La
where
condición especifica de qué padre desea recuperar los descendientes. Puede ampliar esta consulta con más niveles según sea necesario.fuente
parent_id > id
no puede usar esta solución.WITH RECURSIVE
método, el siguiente artículo me pareció realmente útil con diferentes escenarios, como profundidad de recursión, distinciones y ciclos de detección y cierreDesde el blog Gestión de datos jerárquicos en MySQL
Estructura de la mesa
Consulta:
Salida
La mayoría de los usuarios en un momento u otro han tratado con datos jerárquicos en una base de datos SQL y, sin duda, aprendieron que la gestión de datos jerárquicos no es para lo que está destinada una base de datos relacional. Las tablas de una base de datos relacional no son jerárquicas (como XML), sino que son simplemente una lista plana. Los datos jerárquicos tienen una relación padre-hijo que no se representa naturalmente en una tabla de base de datos relacional. Lee mas
Consulte el blog para más detalles.
EDITAR:
Salida:
Referencia: ¿Cómo hacer la consulta SELECCIÓN recursiva en Mysql?
fuente
Prueba estos:
Definición de tabla:
Filas experimentales:
Procedimiento almacenado recursivo:
Función de envoltura para el procedimiento almacenado:
Seleccionar ejemplo:
Salida:
Filtrando filas con cierta ruta:
Salida:
fuente
(20, 'category2', 19), (21, 'category3', 20), (22, 'category4', 20),
El mejor enfoque que se me ocurrió es
Enfoque de linaje descr. se puede encontrar donde sea, por ejemplo aquí o aquí . En cuanto a la función, eso es lo que me inspiró.
Al final, obtuve una solución más o menos simple, relativamente rápida y SIMPLE.
Cuerpo de la función
Y luego solo
Espero que ayude a alguien :)
fuente
Hice lo mismo para otra consulta aquí
Mysql select recursive get all child with multiple level
La consulta será:
fuente
SELECT idFolder, (SELECT GROUP_CONCAT(lv SEPARATOR ',') FROM ( SELECT @pv:=(SELECT GROUP_CONCAT(idFolder SEPARATOR ',') FROM Folder WHERE idFolderParent IN (@pv)) AS lv FROM Folder JOIN (SELECT @pv:= F1.idFolder )tmp WHERE idFolderParent IN (@pv)) a) from folder F1 where id > 10
; No puedo recomendar F1.idFolder para @pvNULL
como resultado. ¿Sabes por qué podría ser eso? ¿Existen requisitos previos en términos del motor de la base de datos, o ha cambiado algo desde que hizo esta respuesta que hace que esta consulta esté desactualizada?Si necesita una velocidad de lectura rápida, la mejor opción es usar una tabla de cierre. Una tabla de cierre contiene una fila para cada par ancestro / descendiente. Entonces, en su ejemplo, la tabla de cierre se vería así
Una vez que tenga esta tabla, las consultas jerárquicas se vuelven muy fáciles y rápidas. Para obtener todos los descendientes de la categoría 20:
Por supuesto, hay un gran inconveniente cada vez que utiliza datos desnormalizados como este. Debe mantener la tabla de cierre junto con su tabla de categorías. Probablemente, la mejor manera es usar disparadores, pero es algo complejo rastrear correctamente las inserciones / actualizaciones / eliminaciones para las tablas de cierre. Como con cualquier cosa, debe analizar sus requisitos y decidir qué enfoque es mejor para usted.
Editar : vea la pregunta ¿Cuáles son las opciones para almacenar datos jerárquicos en una base de datos relacional? Para más opciones. Existen diferentes soluciones óptimas para diferentes situaciones.
fuente
Consulta simple para enumerar la primera recursión del niño:
Resultado:
... con unión izquierda:
La solución de @tincot para enumerar todos los niños:
Pruébelo en línea con Sql Fiddle y vea todos los resultados.
http://sqlfiddle.com/#!9/a318e3/4/0
fuente
Puede hacerlo así en otras bases de datos con bastante facilidad con una consulta recursiva (YMMV sobre rendimiento).
La otra forma de hacerlo es almacenar dos bits adicionales de datos, un valor izquierdo y derecho. Los valores izquierdo y derecho se derivan de un recorrido de preorden de la estructura de árbol que está representando.
Esto se conoce como Recorrido de árbol de pedido anticipado modificado y le permite ejecutar una consulta simple para obtener todos los valores principales a la vez. También se conoce con el nombre de "conjunto anidado".
fuente
Simplemente use BlueM / tree php class para hacer un árbol de una tabla de autorrelación en mysql
Aquí hay un ejemplo del uso de BlueM / tree:
fuente
Es una tabla de categorías .
Salida::
fuente
Es un poco complicado, mira esto si te funciona
Enlace de violín de SQL http://www.sqlfiddle.com/#!2/e3cdf/2
Reemplace con su campo y el nombre de la tabla adecuadamente.
fuente
Algo no mencionado aquí, aunque un poco similar a la segunda alternativa de la respuesta aceptada pero diferente y de bajo costo para consultas de gran jerarquía y elementos fáciles (insertar actualización eliminar), estaría agregando una columna de ruta persistente para cada elemento.
algo como:
Ejemplo:
Optimice la longitud de la ruta y
ORDER BY path
utilice la codificación base36 en lugar de la identificación de ruta numérica realhttps://en.wikipedia.org/wiki/Base36
Suprime también el separador de barra '/' usando longitud fija y relleno para la identificación codificada
Explicación detallada de optimización aquí: https://bojanz.wordpress.com/2014/04/25/storing-hierarchical-data-materialized-path/
QUE HACER
construir una función o procedimiento para dividir el camino para los antepasados retreivos de un elemento
fuente
base36
Esto funciona para mí, espero que esto también funcione para ti. Le dará un conjunto de registros Root a Child para cualquier menú específico. Cambie el nombre del campo según sus requisitos.
fuente
Me resultó más fácil:
1) cree una función que verifique si un elemento está en algún lugar de la jerarquía principal de otro. Algo como esto (no escribiré la función, hágala con WHILE DO):
en tu ejemplo
2) use una sub-selección, algo como esto:
fuente
He hecho una consulta por ti. Esto le dará una categoría recursiva con una sola consulta:
Aquí hay un violín .
fuente