是否可以进行递归SQL查询?

时间:2020-03-05 18:50:25  来源:igfitidea点击:

我有一个与此类似的表:

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会完全实现该标准)。因此,从理论上讲,我们现在可以执行此操作。