是否可以进行递归SQL查询?
我有一个与此类似的表:
CREATE TABLE example ( id integer primary key, name char(200), parentid integer, value integer);
我可以使用parentid字段将数据排列成树形结构。
现在这是我无法解决的问题。给定一个parentid,是否可以编写一条SQL语句以将该parentid下的所有值字段加起来并向下递归树的分支?
更新:我正在使用posgreSQL,因此无法使用精美的MS-SQL功能。无论如何,我希望将其视为通用SQL问题。
顺便说一句,给我留下深刻印象的是在提出问题的15分钟之内有6个答案!去堆栈溢出!
解决方案
回答
这是SQL Server吗?我们不能编写一个TSQL存储过程来循环并将结果合并在一起吗?
我也很感兴趣,但是是否有一种仅SQL的方式可以做到这一点。从我记得我的地理数据库类中得到的信息来看,应该有。
回答
使用通用表表达式。
May want to indicate this is SQL Server 2005 or above only. Dale Ragan
这是有关SqlTeam没有通用表表达式的递归的文章。
回答
我认为使用HierarchyID在SQL 2008中更容易
回答
如果我们使用的是SQL Server 2005,则有一种非常酷的方法可以使用"公共表表达式"来执行此操作。
它消除了创建临时表的所有繁琐工作,并且基本上允许我们仅使用WITH和UNION来完成所有工作。
这是一个很好的教程:
http://searchwindevelopment.techtarget.com/tip/0,289483,sid8_gci1278207,00.html
回答
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
回答
如果要使用可在任何ANSI SQL-92 RDBMS上使用的便携式解决方案,则需要在表中添加一个新列。
Joe Celko是嵌套集方法在SQL中存储层次结构的原始作者。我们可以使用Google"嵌套集"层次结构来了解有关背景的更多信息。
或者,我们可以将parentid重命名为leftid并添加一个rightid。
这里是我总结嵌套集的尝试,由于我不是Joe Celko,嵌套集将严重不足:SQL是基于集的语言,而邻接模型(存储父ID)不是层次结构的基于集的表示。因此,没有查询基于纯模式的邻接模式的方法。
但是,近年来,大多数主要平台都引入了扩展,以解决这一精确问题。因此,如果有人对Postgres特定的解决方案做出答复,请务必使用该解决方案。
回答
如果我们需要存储任意图形,而不仅仅是层次结构,则可以将Postgres推到一边,然后尝试使用诸如AllegroGraph之类的图形数据库:
图数据库中的所有内容都存储为三元组(源节点,边,目标节点),它为我们提供了一流的支持,可操作图结构并使用类似SQL的语言查询它。
它不能与Hibernate或者Django ORM之类的东西很好地集成在一起,但是如果我们对图结构很认真(不仅像Nested Set模型那样的层次结构可以为我们提供),请检查一下它。
我也相信Oracle终于在其最新产品中增加了对真实图的支持,但是我很惊讶它花了这么长时间,很多问题都可以从该模型中受益。
回答
在PostgreSQL中,有几种方法可以满足需求。
- 如果可以安装模块,请查看tablefunc组件。它具有处理遍历树的connectby()函数。 http://www.postgresql.org/docs/8.3/interactive/tablefunc.html
- 还要检查ltree贡献,我们可以修改表以使用: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 = ; if found then return next results; for child in select id from example where parent_id = 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);
回答
下面的代码可以编译,并且已经过测试。
create or replace function subtree (bigint) returns setof example as $$ declare results record; entry record; recs record; begin select into results * from example where parent = ; if found then for entry in select child from example where parent = and child parent loop for recs in select * from subtree(entry.child) loop return next recs; end loop; end loop; end if; return next results; end; $$ language 'plpgsql';
在我的情况下,条件"子<>父"是必需的,因为节点指向自己。
玩得开心 :)
回答
从8.4版开始,PostgreSQL使用SQL标准的" WITH"语法对通用表表达式提供了递归查询支持。
回答
尽管问题已经得到很好的回答,但作为简短说明,应该注意的是,如果我们将其视为:
generic SQL question
那么SQL的实现就很简单了,因为SQL'99允许通过" WITH RECURSIVE"语句在规范中进行线性递归(尽管我相信没有RDBMS会完全实现该标准)。因此,从理论上讲,我们现在可以执行此操作。