是否有可能做一个recursion的SQL查询?

我有一个类似这样的表格:

CREATE TABLE example ( id integer primary key, name char(200), parentid integer, value integer); 

我可以使用parentid字段来将数据排列成一个树形结构。

现在,这是我无法解决的问题。 鉴于一个parentid,是否有可能编写一个SQL语句,将所有值字段加起来,并recursion树的分支?

更新:我使用posgreSQL所以花式MS-SQLfunction不可用。 无论如何,我希望这被视为一个通用的SQL问题。

顺便提一下,在提问的15分钟内有6个答案,我非常感动! 去堆栈溢出!

PostgreSQL中有几种方法可以满足你的需要。

  • 如果你可以安装模块,看看tablefunc contrib。 它有一个处理遍历树的connectby()函数。 http://www.postgresql.org/docs/8.3/interactive/tablefunc.html

  • 另外检查一下你可以调整你的表使用的ltree contrib: http : //www.postgresql.org/docs/8.3/interactive/ltree.html

  • 或者你可以用PL / PGSQL函数自己遍历树。

像这样的东西:

 create or replace function example_subtree (integer) returns setof example as 'declare results record; child record; begin select into results * from example where parent_id = $1; if found then return next results; for child in select id from example where parent_id = $1 loop for temp in select * from example_subtree(child.id) loop return next temp; end loop; end loop; end if; return null; end;' language 'plpgsql'; select sum(value) as value_sum from example_subtree(1234); 

以下是使用公用表expression式的示例脚本:

 with recursive sumthis(id, val) as ( select id, value from example where id = :selectedid union all select C.id, C.value from sumthis P inner join example C on P.id = C.parentid ) select sum(val) from sumthis 

上面的脚本创build了一个名为sumthis的“虚拟”表,它具有列idval 。 它被定义为与union all合并的两个select的结果。

首先select获取根( where id = :selectedid )。

第二个select反复跟随前一个结果的子节点,直到没有任何东西可以返回。

最终结果可以像普通表一样处理。 在这种情况下val列被求和。

从版本8.4开始,PostgreSQL使用SQL标准WITH语法对公用表expression式进行recursion查询支持 。

如果您想要一个可以在任何ANSI SQL-92 RDBMS上工作的便携式解决scheme,则需要在表中添加一个新列。

Joe Celko是嵌套集方法的原始作者,用于在SQL中存储层次结构。 你可以通过谷歌的“嵌套集”层次来了解更多关于背景的信息。

或者你可以重新命名为leftid并添加一个rightid

下面是我总结嵌套集的尝试,因为我不是Joe Celko,所以这个集合会变得非常短暂:SQL是一个基于集合的语言,并且邻接模型(存储父ID)不是基于集合的层次结构表示。 因此,没有纯粹的基于集合的方法来查询邻接模式。

但是 ,大多数主要平台近年来都引入了扩展来处理这个确切的问题。 所以如果有人回复Postgres特定的解决scheme,一定要使用它。

SQL中进行recursion查询的标准方法是recursionCTEPostgreSQL8.4支持它们。

在早期版本中,可以编写一个recursion设置返回函数:

 CREATE FUNCTION fn_hierarchy (parent INT) RETURNS SETOF example AS $$ SELECT example FROM example WHERE id = $1 UNION ALL SELECT fn_hierarchy(id) FROM example WHERE parentid = $1 $$ LANGUAGE 'sql'; SELECT * FROM fn_hierarchy(1) 

看到这篇文章:

  • PostgreSQL中的分层查询

如果您使用SQL Server 2005,那么使用公共表expression式来实现这一点非常酷。

它将创build一个临时表所需的所有工作都放在一边,基本上只需要一个WITH和一个UNION即可完成。

这是一个很好的教程:

http://searchwindevelopment.techtarget.com/tip/0,289483,sid8_gci1278207,00.html

使用公共表格expression式 。

可能只想表明这是SQL Server 2005或更高版本。 戴尔·拉根

这里有一篇关于没有公共表expression式的SqlTeamrecursion的文章 。

下面的代码编译并且testingOK。

创build或replace函数子树(bigint)
返回setof例如$$
宣布
    结果logging;
    录入logging
    logging;
开始
    从父母= $ 1的例子中select结果*
    如果find的话
        用于从父母= $ 1和孩子父母循环的例子中select子女
             select * from子树(entry.child)循环中的recs
                返回下一个recs;
            末端循环;
        末端循环;
    万一;
    返回下一个结果;
结束;
 $$语言'plpgsql';

因为节点指向自己,所以在我的情况下需要条件“child <> parent”。

玩的开心 :)

Oracle有“START WITH”和“CONNECT BY”

 select lpad(' ',2*(level-1)) || to_char(child) s from test_connect_by start with parent is null connect by prior child = parent; 

http://www.adp-gmbh.ch/ora/sql/connect_by.html

尽pipe这个问题已经得到了很好的回答,但应该指出的是,如果我们把这个问题看成是:

一般的SQL问题

那么SQL实现是非常直接的,因为SQL'99允许通过WITH RECURSIVE语句在规范中进行线性recursion(尽pipe我相信没有RDBMS完全实现这个标准)。 所以从理论的angular度来看,我们现在可以做到这一点。

没有一个例子对我有用,所以我修正了这个问题:

宣布
    结果logging;
    录入logging
    logging;
开始
    结果在select*从项目其中pid = $ 1循环
        返回下一个结果;
         select * from project_subtree(results.id)循环中的recs
            返回下一个recs;
        末端循环;
    末端循环;
    返回;
结束;

这是SQL Server吗? 难道你不能写一个循环的TSQL存储过程,并将结果联合在一起?

我也有兴趣,如果有这样做,但只有SQL的方式。 从我从地理数据库课上记得的一点,应该有。

我认为在SQL 2008中使用HierarchyID更容易

如果你需要存储任意的graphics,而不仅仅是层次结构,你可以将Postgres推到一边并尝试一个graphics数据库,比如AllegroGraph :

graphics数据库中的所有内容都以三元forms存储(源节点,边,目标节点),并为您提供一stream的支持来操作graphics结构并使用类似SQL的语言查询它。

它不能与Hibernate或Django ORM等很好的集成在一起,但是如果你对图结构(不仅仅是像Nested Set模型这样的层次结构)认真对待,

我也相信Oracle最终在他们的最新产品中增加了对真实graphics的支持,但是我惊讶地发现它花了这么长时间,很多问题都可以从这个模型中受益。