是否可以进行递归 SQL 查询?
我有一个与此类似的表:
CREATE TABLE example (
id integer primary key,
name char(200),
parentid integer,
value integer);
我可以使用parentid 字段将数据排列成树结构。
现在这是我无法解决的一点。 给定一个parentid,是否可以编写一条SQL语句来累加该parentid下的所有值字段并向下递归树的分支?
更新:我正在使用 posgreSQL,因此我无法使用精美的 MS-SQL 功能。 无论如何,我希望将其视为一个通用的 SQL 问题。
I have a table similar to this:
CREATE TABLE example (
id integer primary key,
name char(200),
parentid integer,
value integer);
I can use the parentid field to arrange data into a tree structure.
Now here's the bit I can't work out. Given a parentid, is it possible to write an SQL statement to add up all the value fields under that parentid and recurse down the branch of the tree ?
UPDATE: I'm using posgreSQL so the fancy MS-SQL features are not available to me. In any case, I'd like this to be treated as a generic SQL question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
在
SQL
中进行递归查询的标准方法是递归CTE
。PostgreSQL
从8.4
开始支持它们。在早期版本中,您可以编写递归设置返回函数:
请参阅本文:
A standard way to make a recursive query in
SQL
are recursiveCTE
.PostgreSQL
supports them since8.4
.In earlier versions, you can write a recursive set-returning function:
See this article:
以下代码可以编译并测试正常。
在我的例子中需要条件“child <>parent”,因为节点指向它们自己。
The following code compiles and it's tested OK.
The condition "child <> parent" is needed in my case because nodes point to themselves.
如果您想要一个可在任何 ANSI SQL-92 RDBMS 上运行的便携式解决方案,您将需要向表中添加新列。
Joe Celko 是嵌套集方法的原始作者在 SQL 中存储层次结构。 您可以通过 Google “嵌套集”层次结构了解有关的背景。
或者您可以将parentid重命名为leftid并添加rightid。
这是我尝试总结嵌套集的尝试,但它会严重不足,因为我不是 Joe Celko:SQL 是一种基于集合的语言,并且邻接模型(存储父 ID)不是层次结构的基于集合的表示。 因此,不存在纯粹的基于集合的方法来查询邻接模式。
但是,大多数主要平台近年来都引入了扩展来解决这个具体问题。 因此,如果有人回复 Postgres 特定的解决方案,请务必使用它。
If you want a portable solution that will work on any ANSI SQL-92 RDBMS, you will need to add a new column to your table.
Joe Celko is the original author of the Nested Sets approach to storing hierarchies in SQL. You can Google "nested sets" hierarchy to understand more about the background.
Or you can just rename parentid to leftid and add a rightid.
Here is my attempt to summarize Nested Sets, which will fall woefully short because I'm no Joe Celko: SQL is a set-based language, and the adjacency model (storing parent ID) is NOT a set-based representation of a hierarchy. Therefore there is no pure set-based method to query an adjacency schema.
However, most of the major platforms have introduced extensions in recent years to deal with this precise problem. So if someone replies with a Postgres-specific solution, use that by all means.
从 8.4 版本开始,PostgreSQL 为公共表表达式提供了递归查询支持使用 SQL 标准
WITH
语法。Since version 8.4, PostgreSQL has recursive query support for common table expressions using the SQL standard
WITH
syntax.这是 SQL Server 吗? 您不能编写一个 TSQL 存储过程来循环并将结果合并在一起吗?
我也很感兴趣是否有一种仅 SQL 的方法可以做到这一点。 从我在地理数据库课上的记忆来看,应该有。
is this SQL Server? Couldn't you write a TSQL stored procedure that loops through and unions the results together?
I am also interested if there is a SQL-only way of doing this though. From the bits I remember from my geographic databases class, there should be.
这些示例对我来说都不起作用,所以我像这样修复了它:
None of the examples worked OK for me so I've fixed it like this:
顺便说一句,尽管这个问题已经得到很好的回答,但应该指出的是,如果我们将其视为:
,那么 SQL 实现相当简单,因为 SQL'99 允许通过
WITH RECURSIVE
语句在规范中进行线性递归(尽管我相信没有 RDBMS 完全实现该标准)。 所以从理论角度来看我们现在就可以做到这一点。Just as a brief aside although the question has been answered very well, it should be noted that if we treat this as a:
then the SQL implementation is fairly straight-forward, as SQL'99 allows linear recursion in the specification (although I believe no RDBMSs implement the standard fully) through the
WITH RECURSIVE
statement. So from a theoretical perspective we can do this right now.Oracle 有“开始”和“连接”
http://www.adp -gmbh.ch/ora/sql/connect_by.html
Oracle has "START WITH" and "CONNECT BY"
http://www.adp-gmbh.ch/ora/sql/connect_by.html
下面是一个使用通用表表达式的示例脚本:
上面的脚本创建了一个名为
sumthis
的“虚拟”表,其中包含列id
和val
。 它被定义为使用union all
合并两个选择的结果。首先
select
获取根(where id = :selectedid
)。第二个
select
迭代地跟踪先前结果的子项,直到没有任何内容可返回。然后可以像普通表一样处理最终结果。 在这种情况下,val 列被求和。
Here is an example script using common table expression:
The script above creates a 'virtual' table called
sumthis
that has columnsid
andval
. It is defined as the result of two selects merged withunion all
.First
select
gets the root (where id = :selectedid
).Second
select
follows the children of the previous results iteratively until there is nothing to return.The end result can then be processed like a normal table. In this case the val column is summed.
有几种方法可以在 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 函数自己遍历树。
像这样的事情:
There are a few ways to do what you need in PostgreSQL.
If you can install modules, look at the tablefunc contrib. It has a connectby() function that handles traversing trees. http://www.postgresql.org/docs/8.3/interactive/tablefunc.html
Also check out the ltree contrib, which you could adapt your table to use: http://www.postgresql.org/docs/8.3/interactive/ltree.html
Or you can traverse the tree yourself with a PL/PGSQL function.
Something like this:
如果您需要存储任意图形,而不仅仅是层次结构,您可以将 Postgres 推到一边并尝试图形数据库,例如 AllegroGraph:
图形数据库中的所有内容都存储为三元组(源节点、边缘、目标节点),它为操作图形结构并使用类似 SQL 的语言查询它提供了一流的支持。
它与 Hibernate 或 Django ORM 之类的东西集成得不好,但如果您认真对待图形结构(不仅仅是像 Nested Set 模型给您的层次结构),请检查一下。
我还相信 Oracle 最终在其最新产品中添加了对真实图形的支持,但我很惊讶它花了这么长时间,很多问题都可以从这个模型中受益。
If you need to store arbitrary graphs, not just hierarchies, you could push Postgres to the side and try a graph database such as AllegroGraph:
Everything in the graph database is stored as a triple (source node, edge, target node) and it gives you first class support for manipulating the graph structure and querying it using a SQL like language.
It doesn't integrate well with something like Hibernate or Django ORM but if you are serious about graph structures (not just hierarchies like the Nested Set model gives you) check it out.
I also believe Oracle has finally added a support for real Graphs in their latest products, but I'm amazed it's taken so long, lots of problems could benefit from this model.