2010-06-25 4 views
4

Je sais qu'il y a un moyen facile de le faire, mais mes capacités de récursivité sont hors de la pratique. Compte tenu d'une table de base de données qui comporte trois champs:Appels récursifs à la base de données en perl

id 
label 
child_id 

Je devrais être en mesure de mettre en place une fonction récursive qui donne une sortie comme ceci:

child (input of program) 
    parent1 
    parent2 
    grandparent1 
     great-grandparent1 
    grandparent2 
    grandparent3 
    parent3 
    grandparent4 
    grandparent5 

Je sais que ce devrait être facile, mais je peux Je n'ai pas envie de passer par la gymnastique mentale pour que ça marche. Aussi, est-ce une bonne chose à faire? On dirait que je pourrais finir par laisser ouvert quelques connexions de base de données.

Je pense que c'est la partie la rendant difficile pour moi. Je commence avec un child_id, et mon chemin vers le haut. Et un enfant peut avoir beaucoup de parents. Ainsi, la sortie serait l'identifiant de l'enfant à la racine de l'arbre et ensuite les parents et les grands-parents pour chaque branche. Plus j'y pense, c'est juste la formule traditionnelle 'un parent, beaucoup de grands-parents', sauf pour la sémantique. Je pourrais juste être en train de penser ça.

Le tableau ressemblerait à quelque chose comme ceci:

table parents 

id child_id label 
1  NULL  child 
2  1   parent1 
3  1   parent2 
4  1   parent3 
5  3   grandparent1 
6  3   grandparent2 
7  3   grandparent3 
8  5   great-grandparent1 
9  4   grandparent4 
10  4   grandparent5 
+0

Selon quels critères emboîtez-vous votre sortie? – Zaid

+0

Vous savez, j'ai omis une partie importante (et, je pense, la partie qui la rend confuse pour moi). Je commence avec un child_id, et mon chemin vers le haut. Et un enfant peut avoir beaucoup de parents. Ainsi, la sortie serait l'identifiant de l'enfant à la racine de l'arbre et ensuite les parents et les grands-parents pour chaque branche. –

+1

Quelle est la taille de votre table? Il pourrait être beaucoup plus facile de charger ceci dans une structure de données et de le faire en mémoire en appelant la base de données. Est-ce à court de mémoire un problème ici? – Mike

Répondre

3

Vous pouvez essayer cette façon

sub getChildren { 
    my $id = shift; 
    my $depth = shift; 
    my $sql = qq/SELECT id,label,child_id FROM table WHERE id=?/; 
    my $sth = $db->prepare($sql); 
    my $sth->execute($id); 
    while(my ($id,$label,$child_id)=$sth->fetchrow_array) { 
    print " "x$depth,$label; 
    getChildren($child_id,$depth++); 
} 
} 
getChildren($id); 
+0

Génial.C'est à peu près ce que j'essayais de faire, mais j'essayais d'utiliser une profondeur globale de $ pour une raison quelconque. Si vous lisez ma note ci-dessus, je commence réellement avec les enfants, mais je pense que le même concept fonctionnera. –

+0

Vous n'avez besoin de préparer la déclaration qu'une seule fois. Ou utilisez prepare_cached(). – runrig

+0

Le compteur de profondeur $ continue de compter, même s'il doit être réinitialisé, pour une raison quelconque. Je pense qu'un préfixe est plus approprié ici (++ $ depth), mais il a toujours le même problème de toute façon. –

0

En fait, j'expliqué un problème assez similaire dans mon blog, Implementing a depth first search in a PostgreSQL stored procedure, et ma façon de résoudre ce en utilisant perl.

Si votre base de données ne prend pas en charge les procédures stockées, vous pouvez faire la même chose côté client, mais vous devez d'abord récupérer la totalité de la table et le faire en mémoire.

Vous pouvez bien sûr le faire de manière récursive et récupérer chaque entrée au fur et à mesure, mais elle ne sera pas mise à l'échelle en raison du surdébit de l'instruction SQL (sauf peut-être sur SQLite). Si la performance n'est pas un problème, cela doit être de loin la solution la plus simple.

Questions connexes