WITH RECURSIVE Query Postgres的可能解释

时间:2016-06-17 11:38:02

标签: sql postgresql common-table-expression

我一直在阅读Postgres中的Query。

这令我感到惊讶
WITH RECURSIVE t(n) AS (
    VALUES (1)
  UNION ALL
    SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;

我无法理解查询的评估是如何运作的。

  • t(n)它听起来像一个带参数的函数。如何传递n的值。

有关SQL中递归语句如何发生故障的任何见解。

2 个答案:

答案 0 :(得分:4)

这称为公用表表达式,是一种在SQL中表达递归查询的方法:

t(n)将CTE的名称定义为t,其中一列名为n。它类似于派生表的别名:

select ... 
from (
  ...
) as t(n);

递归以值1开始(即values (1)部分),然后递归加1,直到达到99。因此它生成从1到99的数字。然后最终查询然后总结所有这些数字。

n是一个列名,不是一个&#34;变量&#34;和#34;任务&#34;以与任何数据检索相同的方式发生。

WITH RECURSIVE t(n) AS (
    VALUES (1) --<< this is the recursion "root"
  UNION ALL
    SELECT n+1 FROM t WHERE n < 100 --<< this is the "recursive part"
)
SELECT sum(n) FROM t;

如果你&#34;展开&#34;递归(实际上是一个迭代)然后你最终得到这样的东西:

select x.n + 1
from (
  select x.n + 1
  from (
    select x.n + 1
    from (
      select x.n + 1
      from (
         values (1)
      ) as x(n) 
    ) as x(n)
  ) as x(n)
) as x(n)

手册中的更多细节:
https://www.postgresql.org/docs/current/static/queries-with.html

答案 1 :(得分:0)

如果您正在寻找它的评估方式,则递归分两个阶段进行。

  1. 根执行一次。
  2. 执行递归部分,直到不返回任何行。在这一点上,文档有点模糊。
  3. 现在,通常在数据库中,当我们进行命令式编程时,我们会以与我们想到的不同的方式来思考“功能”。在数据库术语中,思考函数的最佳方式是“对应每个域值的对应关系,您只有一个对应的值”。因此,当前的挑战之一就是停止在编程功能方面进行思考。甚至用户定义的函数最好以另一种方式考虑,因为它避免了关于运行查询和查询规划器的交叉点的很多潜在的麻烦...所以它可能看起来像一个函数,但这是不正确的。

    相反,WITH子句使用不同的,几乎相反的符号。在这里,你有一个名称t,在元组结构(n)后面(在这种情况下可选)。所以这不是带参数的函数,而是与结构的关系。

    所以这会如何分解:

    SELECT 1 as n where n < 100
    UNION ALL
    SELECT n + 1 FROM (SELECT 1 as n) where n < 100
    UNION ALL
    SELECT n + 1 FROM (SELECT n + 1 FROM (SELECT 1 as n)) where n < 100
    

    当然这是一种简化,因为在内部我们会跟踪cte状态并继续加入最后一次迭代,所以在实践中这些会折回到接近线性的复杂度(而上面的图表表明性能要差得多)

    所以实际上你会得到更像的东西:

     SELECT 1 as n where 1 < 100
     UNION ALL
     SELECT 1 + 1 as n where 1 + 1 < 100
     UNION ALL
     SELECT 2 + 1 AS n WHERE 2 + 1 < 100
     ...
    

    本质上,以前的值继续存在。