【问题标题】:Recursive calls to database in perlperl中对数据库的递归调用
【发布时间】:2010-06-25 17:57:35
【问题描述】:

我知道有一种简单的方法可以做到这一点,但我的递归能力已经过时了。给定一个包含三个字段的数据库表:

id
label
child_id

我应该能够组合一个递归函数,输出如下:

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

我知道这应该很容易,但我无法通过心理体操来让它发挥作用。另外,这是一件好事吗?似乎我最终可能会打开相当多的数据库连接。

我认为这是让我感到困难的部分。我从一个 child_id 开始,然后一路向上。一个孩子可以有很多父母。因此,输出将是树“根”处的子 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

【问题讨论】:

  • 根据什么标准嵌套输出?
  • 你知道,我遗漏了一个重要的部分(而且,我认为,让我感到困惑的部分)。我从一个 child_id 开始,然后一路向上。一个孩子可以有很多父母。因此,输出将是树“根”处的子 ID,然后是每个分支的父母和祖父母。
  • 你的桌子有多大?将其加载到数据结构中并在内存中执行与调用数据库相比可能要容易得多。内存不足是这里的问题吗?
  • imo,您通常最好使用具有 ID、标签、ParentID 的表结构(根节点/记录应该有一个 null/零 parentID)。递归函数应接受 1 个参数:ParentID。遍历结果集,将 ID 传递给您的 Recursion Fcn。从逻辑上讲,如果没有子记录(即没有具有此父 ID 的记录),您将不会递归。当然,如果您的查询通过分组来计算子节点的数量并且如果计数为零甚至不递归,那么效率会更高。
  • label2 是否在 label1 的子级或父级之上? label1 是否有 label2 的 child_id,还是相反?我最初认为 label2 将是 label1 的孩子,但是您的“孩子有很多父母”让我感到困惑并重新思考。一个小的示例数据有很长的路要走。

标签: database perl recursion self-reference


【解决方案1】:

你可以试试这个方法

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);

【讨论】:

  • 太棒了。这就是我想要做的事情,但出于某种原因我试图使用全局 $depth 。如果您阅读了我上面的说明,我实际上是从孩子们开始的,但我认为同样的概念也可以。
  • 您只需要准备一次声明。或者使用 prepare_cached()。
  • $depth 计数器不断计数,即使出于某种原因它应该重置。我认为前缀在这里更合适(++$depth),但无论如何它仍然存在相同的问题。
  • 没关系,想通了。 $depth++ 增量器需要位于 while 循环之外。
【解决方案2】:

我实际上在我的博客Implementing a depth first search in a PostgreSQL stored procedure 中解释了一个非常相似的问题,以及我使用 perl 解决这个问题的方法。

如果您的数据库不支持存储过程,您可以在客户端执行相同的操作,但您需要先获取整个表并在内存中执行。

您当然可以递归地执行此操作并在执行过程中获取每个条目,但由于 SQL 语句开销(可能在 SQLite 上除外),它不会扩展。如果性能不是问题,这一定是迄今为止最简单的解决方案。

【讨论】:

    猜你喜欢
    • 2014-08-02
    • 2015-06-19
    • 1970-01-01
    • 2010-11-04
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多