Conjuntos anidados de MySQL: ¿cómo encontrar el padre del nodo?
-
05-07-2019 - |
Pregunta
Tengo su configuración de tipo de jerarquía de conjunto anidado común y corriente con las siguientes columnas:
nombre de la tabla:
myset
columnas:
id, name, lft, rgt
¿Alguien conoce una consulta para determinar el padre de un nodo?
Leí un par de lugares en los que es útil tener también un Identificación de los padres en su tabla para realizar un seguimiento de esto, pero parece redundante y parece que podría desincronizarse con el conjunto anidado si una consulta se ejecutó incorrectamente al agregar/eliminar/mover algo dentro del conjunto.
Solución
Mira a esta pregunta.Es parecido al tuyo.He publicado allí una consulta que puede necesitar.
SELECT title, (SELECT TOP 1 title
FROM tree t2
WHERE t2.lft < t1.lft AND t2.rgt > t1.rgt
ORDER BY t2.rgt-t1.rgt ASC) AS parent
FROM tree t1
ORDER BY rgt-lft DESC
Espero que haya lo que necesitas.
Para la siguiente tabla:
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
| 7 | MP3 PLAYERS | 11 | 14 |
| 8 | FLASH | 12 | 13 |
| 9 | CD PLAYERS | 15 | 16 |
| 10 | 2 WAY RADIOS | 17 | 18 |
produce la salida:
title | parent
----------------------------------------------
ELECTRONICS | NULL
PORTABLE ELECTRONICS | ELECTRONICS
TELEVISIONS | ELECTRONICS
MP3 PLAYERS | PORTABLE ELECTRONICS
FLASH | MP3 PLAYERS
CD PLAYERS | PORTABLE ELECTRONICS
2 WAY RADIOS | PORTABLE ELECTRONICS
TUBE | TELEVISIONS
LCD | TELEVISIONS
PLASMA | TELEVISIONS
Otros consejos
TOP es un comando MSSQL, use LIMIT para MySQL:
SELECT title, (SELECT title
FROM tree t2
WHERE t2.lft < t1.lft AND t2.rgt > t1.rgt
ORDER BY t2.rgt-t1.rgt ASC
LIMIT 1)
AS parent FROM tree t1
ORDER BY (rgt-lft) DESC
Debería hacer el truco ..
solo para agregar a estas respuestas que me ayudaron mucho,
Necesitaba encontrar el padre inmediato de un nodo, así como el padre de nivel superior de una cadena de nodo en algunos casos,
utilicé lo siguiente como base para obtener los artículos en orden de hijo a padre
SELECT parent.* FROM
nested_set node,
nested_set parent
WHERE (
node.set_left BETWEEN parent.set_left AND parent.set_right
)
AND node.set_id={CHILD_NODE_ID_HERE}
ORDER BY parent.set_right - parent.set_left
#LIMIT 1,1
entonces se trata de agregar LIMIT 1,1
para capturar solo la segunda fila que sería la principal inmediata
también debe tenerse en cuenta que con la consulta anterior si el nodo en sí es el padre de nivel superior, NO tendría un padre inmediato , por lo que con el >= <=
debería devolver un conjunto de resultados vacío
para obtener el padre de nivel superior, revertí el orden por cláusula, incluí una verificación si el nodo en sí mismo es el padre superior y limité el resultado a la primera fila
SELECT parent.* AS top_level_right FROM
nested_set node,
nested_set parent
WHERE (
node.set_left >= parent.set_left
AND node.set_left <= parent.set_right
)
AND node.set_id={CHILD_NODE_ID_HERE}
ORDER BY parent.set_left - parent.set_right
LIMIT 1
en la última consulta utilicé operadores <=> para que el rango seleccionado abarque el nodo secundario si también resulta ser el nivel superior primario
Tuve un problema con la consulta de Lucasz. Mi versión de mysql no entendió el comando TOP. Tuve que usar LIMIT en su lugar. Aquí está el código revisado.
SELECT
`id`,
(SELECT
`id`
FROM
`[*** YOUR TABLE ***]` AS `t2`
WHERE
`t2`.`left_id` < `t1`.`left_id`AND
`t2`.`right_id` > `t1`.`right_id`
ORDER BY
`t2`.`right_id`-`t1`.`right_id`ASC
LIMIT
1) AS `parent`
FROM
`[*** YOUR TABLE ***]` AS `t1`
WHERE
`t1`.`id` = [*** ID OF THE NODE WHOS PARENT YOU WISH TO LOOKUP ***]
ORDER BY
`right_id`-`left_id` DESC
Obviamente, cambie las cosas en [] 'para satisfacer sus necesidades. También quite los [] 's. Esta consulta solo devuelve UNA fila. Me gusta así ...
id parent
7 3
select * from myset
where lft < :lftOfCurrent and rgt > :lftOfCurrent
order lft desc
limit 1
Podría usar un máximo en lugar de un orden / límite y podría necesitar otra palabra clave para limitar los resultados a una fila dependiendo de su base de datos. Entre más que & Lt; y > funcionaría si su base de datos devuelve el conjunto exclusivo, que MySQL no lo hace.
SELECT parent.name
FROM myset AS node, myset AS parent
WHERE parent.lft < node.lft
AND parent.rgt > node.rgt
AND node.id = {YOUR CATEGORY ID}
ORDER BY ( parent.rgt - parent.lft ) ASC LIMIT 1;
Todos los ancestros son devueltos por
SELECT id FROM thetable
WHERE x BETWEEN lft and rgt;
Entonces, el padre directo es el antepasado con la menor diferencia entre lft y rgt.
SELECT id FROM thetable
WHERE x BETWEEN lft and rgt
ORDER BY (rgt-lft)
LIMIT 1
El código de spankmaster79 no estaba completamente equivocado. Modifiqué su código y funcionó.
SELECT parent . * FROM Nested_Category AS node, Nested_Category AS parent
enter code hereWHERE node.leftSide
BETWEEN parent.leftSide
AND parent.rightSide
AND node.id ='Enter the Node ID'
ORDER BY (
parent.rightSide - parent.leftSide
)
LIMIT 1 , 1