2010-08-16 3 views
3

J'ai une table (id, parent_id, data)parent_id pointe vers une autre ligne dans la même table (ou est nulle).Des requêtes pour obtenir tous les ancêtres/descendants d'un arbre dans un db?

Existe-t-il un moyen standard pour interroger (1) tous les ancêtres d'un certain ID et (2) tous les descendants d'un certain ID?

Je le fais également en DBIx::Class, donc s'il y a un moyen plus pratique de le faire avec ce module (ou un autre), j'aimerais beaucoup en entendre parler également.

EDIT: clarifie - tous les parents = tous les ancêtres, tous les enfants = tous les descendants.

+0

Juste parents/enfants, ou tous les ancêtres/descendants? En outre, quelle saveur de SQL utilisez-vous? –

+0

Vous cherchez à être un peu agnostique SQL; notre développement db est SQLite, mais la production sera probablement MySQL. – Carl

+0

Voir aussi http://en.wikipedia.org/wiki/Nested_set_model – reinierpost

Répondre

1

Il semble que nous allons pour aller avec DBIx::Class::Tree::AdjacencyList en ce moment. Il fait presque tout ce que je cherchais (pas de résultats ancêtres, malheureusement - mais nous pouvons contourner cela en abordant les questions que nous devons poser de l'autre côté).

Cependant, @ la réponse de Grrrr m'a fait penser, et nous pouvons ajouter une table séparée + module de (id, record_type, record_ancestors) qui attacher à nos modèles qui ont une colonne parent_id et fournir une ancestors ResultSet (essentiellement en faisant un search_rs où l'identification est en la division de la rangée des ancêtres pertinents par w/e délimiteur que nous choisissons). C'est un bon travail juste pour obtenir un tel ensemble de résultats, donc nous n'irons probablement là que si nous trouvons des questions où il est vraiment impossible de demander "est-ce un enfant de parent x" et vraiment besoin "est-ce un parent de enfant x "?

EDIT: ou peut-être que nous utiliserons DBIx::Class::Tree::Mobius - bien qu'il semble que l'affichage de la table brute soit incompréhensible.

+1

Il serait très facile pour vous d'ajouter une méthode 'ancestors' à vos classes Row, soit en l'ajoutant directement dans vos classes' Result' ou en créant un nouveau composant qui sous-classe AdjacencyList et ajoute la méthode dont vous avez besoin. Ou peut-être pourriez-vous arrêter par # dbix-class et discuter avec nous de l'ajout de la fonctionnalité à AdjacencyList elle-même; cela semble être une chose assez raisonnable à avoir. – hobbs

+0

@hobbs: mon collaborateur sur ce projet a offert un correctif en ajoutant un resultset ancêtres à AdjacencyList (pas sûr de quel id il publie sous, et il n'a pas assez de rep de SO pour faire son propre commentaire). – Carl

3

Cela dépend fortement de la saveur de SQL que vous utilisez.

Dans Oracle, vous pouvez utiliser la construction START WITH id = yourid CONNECT BY PRIOR id = parent_id. Dans PostgreSQL, vous pouvez utiliser une fonction connectby('tablename', 'id', 'parent_id', 'id', value, 0).

Dans de nombreux cas, il est logique de représenter des arbres différemment, en définissant une colonne qui contiendra, pour chaque noeud, un chemin complet de l'élément racine à ce noeud.

Il y a des exemples beaucoup de cette technique à trouver sur Internet, le plus récent que j'ai vu, qui traite aussi des DBIx::Class, se trouve ici: http://blogs.perl.org/users/ovid/2010/05/threaded-forum-sql.html

+0

Une des choses que je fais régulièrement avec cet arbre est de déplacer des nœuds dans l'arborescence. Cela semble vaguement douloureux re ayant une colonne qui stocke toute la liste des ancêtres. Je suppose que surcharger la mise à jour pour le faire correctement ne serait pas trop mauvais. – Carl

+0

eeeeeh ... sauf pour la partie en cascade. – Carl

Questions connexes