Ensembles imbriqués MySQL - Comment trouver le parent du noeud?
-
05-07-2019 - |
Question
Votre configuration de type de hiérarchie d'ensembles imbriqués est définie avec les colonnes suivantes:
nom de la table:
myset
colonnes:
id, name, lft, rgt
Quelqu'un connaît-il une requête pour déterminer le parent d'un nœud?
J'ai lu quelques endroits où il est pratique d'avoir également une colonne parent_id dans votre tableau pour garder une trace de cela, mais cela semble redondant et il semble que cela pourrait ne plus être synchronisé avec l'imbrication définir si une requête a été mal exécutée lors de l'ajout / la suppression / du déplacement d'un élément dans l'ensemble.
La solution
Regardez cette question . C'est semblable au vôtre. J'ai posté une requête dont vous pourriez avoir besoin.
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
J'espère qu'il y a ce dont vous avez besoin.
Pour le tableau suivant:
+-------------+----------------------+-----+-----+
| 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 |
il produit le résultat:
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
Autres conseils
TOP est une commande MSSQL, utilisez LIMIT for 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
Devrait faire l'affaire.
juste pour ajouter à ces réponses qui m'a beaucoup aidé,
je devais trouver le parent immédiat d'un nœud, ainsi que le parent de niveau supérieur d'une chaîne de nœuds dans certains cas,
J'ai utilisé les éléments suivants comme base pour obtenir les éléments dans l'ordre parent-parent
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
il s’agit alors d’ajouter le LIMIT 1,1
pour ne capturer que la deuxième ligne qui serait le parent immédiat
il convient également de noter qu'avec la requête ci-dessus, si le nœud lui-même est le parent de niveau supérieur, il ne disposerait donc pas d'un parent immédiat . Par conséquent, avec le >= <=
, il devrait renvoyer jeu de résultats vide
pour obtenir le parent de niveau supérieur, j'ai inversé la clause order by, inclus une vérification si le nœud lui-même est le parent supérieur et limité le résultat à la première ligne
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
dans la dernière requête, j'ai utilisé <=> des opérateurs pour que la plage sélectionnée englobe le nœud enfant s'il s'avère également être le parent de niveau supérieur
J'ai eu un problème avec la requête de Lucasz. Ma version de mysql ne comprenait pas la commande TOP. J'ai dû utiliser LIMIT à la place. Voici le code révisé.
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
Évidemment, modifiez les éléments dans les [] en fonction de vos besoins. Supprimez également les []. Cette requête ne renvoie qu'une ligne. Comme si ...
id parent
7 3
select * from myset
where lft < :lftOfCurrent and rgt > :lftOfCurrent
order lft desc
limit 1
Vous pouvez utiliser un maximum plutôt que l'ordre / limite et vous aurez peut-être besoin d'un autre mot clé pour limiter les résultats à une ligne, en fonction de votre base de données. Entre plutôt que & Lt; et > fonctionnerait si votre base de données renvoie l'ensemble exclusif, ce que MySQL ne fait pas.
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;
Tous les ancêtres sont renvoyés par
SELECT id FROM thetable
WHERE x BETWEEN lft and rgt;
Le parent direct est donc l'ancêtre avec la plus petite différence entre lft et rgt.
SELECT id FROM thetable
WHERE x BETWEEN lft and rgt
ORDER BY (rgt-lft)
LIMIT 1
Le code de spankmaster79 n'était pas complètement faux. J'ai modifié son code et cela a fonctionné.
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