2010-06-25 3 views
4

Я знаю, что есть простой способ сделать это, но мои способности к рекурсии не практичны. Учитывая таблицу базы данных, которая имеет три поля:Рекурсивные вызовы в базу данных в perl

id 
label 
child_id 

я должен быть в состоянии собрать рекурсивную функцию, которая будет давать такой вывод:

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

Я знаю, что это должно быть легко, но я могу «Я хочу, чтобы я прошел через ментальную гимнастику, чтобы заставить ее работать. Кроме того, это хорошая вещь? Похоже, я мог бы в итоге оставить несколько соединений с базами данных.

Я думаю, что это часть, которая затрудняет для меня. Я начинаю с child_id и работаю. И у ребенка может быть много родителей. Таким образом, результатом будет дочерний идентификатор в «корне» дерева, а затем это родители и дедушки и бабушки для каждой ветки. Чем больше я думаю об этом, это просто традиционная формула «один родитель, многие бабушки и дедушки», за исключением семантики. Я просто мог подумать об этом.

таблица будет выглядеть примерно так:

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

По каким критериям вы можете вложить свой выход? – Zaid

+0

Знаете, я оставил важную часть (и, я думаю, ту часть, которая делает это запутанным для меня). Я начинаю с child_id и работаю. И у ребенка может быть много родителей. Таким образом, результатом будет дочерний идентификатор в «корне» дерева, а затем это родители и дедушки и бабушки для каждой ветки. –

+1

Насколько велика ваша таблица? Это может быть намного проще загрузить в структуру данных и сделать это в памяти и вызвать базу данных. Здесь проблема нехватки памяти? – Mike

ответ

3

Вы могли бы попробовать этот способ

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

Awesome.Это о том, что я пытался сделать, но по какой-то причине я пытался использовать глобальную глубину $. Если вы прочтете мое примечание выше, я на самом деле начинаю с детей, но думаю, что эта же концепция будет работать. –

+0

Вам нужно только подготовить заявление один раз. Или используйте prepare_cached(). – runrig

+0

Счетчик $ depth продолжает подсчитывать, даже если он должен сбрасываться по какой-либо причине. Я думаю, что здесь префикс более уместен (++ $ depth), но он по-прежнему имеет одну и ту же проблему. –

0

я на самом деле объясняется довольно аналогичной проблемой в моем блоге, Implementing a depth first search in a PostgreSQL stored procedure, и мой путь решения этой используя perl.

Если ваша база данных не поддерживает хранимые процедуры, вы можете сделать то же самое на стороне клиента, но сначала вам нужно сначала собрать всю таблицу и сделать это в памяти.

Вы можете, конечно, сделать это рекурсивно и получить каждую запись, когда вы идете вперед, но она не будет масштабироваться из-за служебных данных SQL-запроса (кроме, может быть, SQLite). Если производительность не является проблемой, это должно быть самым простым решением.