Comment récupérer tous les frères et sœurs à l'aide du modèle de tables de fermeture SQL (sans sous-requête!)


user3845133

J'essaie d'implémenter le modèle de table de fermeture pour un modèle de menu simple, mais j'ai rencontré quelques difficultés à construire la requête pour trouver tous les frères et sœurs du nœud actuel sans sous-requêtes (par exemple avec des jointures).

Il y a une vieille question très similaire à la mienne mais qui ne semble pas avoir de réponse (ou du moins je ne l'ai pas comprise).

Prenez par exemple le scénario simplifié suivant (n'inclut pas les enregistrements de profondeur zéro):

menu:
+--+--------------+
| id | title      |
+--+--------------+
| 1  | Link 1     |  
| 2  | Link 1.1   | 
| 3  | Link 1.2   | 
| 4  | Link 1.3   | 
| 5  | Link 1.3.1 | 
| 6  | Link 1.3.2 |
+----+------------+

menu_closure:
+----------+------------+-------+
| ancestor | descendant | depth |
+----------+------------+-------+
| 1        | 2          | 1     |
| 1        | 3          | 1     |
| 1        | 4          | 1     |
| 1        | 5          | 2     |
| 1        | 6          | 2     |
| 4        | 5          | 1     |
| 4        | 6          | 1     |
+----------+------------+-------+

Je veux obtenir tous les frères et sœurs du Link 1.1 (id = 2) -> Link 1.2 (id = 3) et Link 1.3 (id = 4).

Remarque: je ne connais que l'identifiant de l' menuenregistrement ciblé .

Actuellement, je fais ce qui suit:

SELECT m.*
FROM menu AS m
LEFT JOIN menu_closure AS mc ON mc.descendant=m.id
WHERE m.id != 2
    AND mc.depth = 1
    AND mc.ancestor = (SELECT ancestor FROM menu_closure WHERE descendant=3 AND depth=1)

Une autre option à laquelle je pensais était d'obtenir d'abord le parent de Link 1.1, puis de récupérer ses enfants en excluant l'identifiant de Link 1.1, mais je recherche une solution avec une seule requête.

Olaf Dietsche

Vous vérifiez d'abord le ancestor

select *
from menu_closure a
where a.descendant = 2

puis prends les frères et sœurs

select *
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
where a.descendant = 2

à la même profondeur que "Link 1.1"

select *
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
where a.descendant = 2
    and s.depth = a.depth

ajouter dans les titres du menu

select *
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
join menu m on m.id = s.descendant
where a.descendant = 2
    and s.depth = a.depth

et exclure tout ce qui n'est pas voulu

select m.*
from menu_closure a
join menu_closure s on s.ancestor = a.ancestor
join menu m on m.id = s.descendant
where a.descendant = 2
    and s.depth = a.depth
    and m.id <> 2

Sqlfiddle final

Articles connexes