非递归语句中的递归调用

时间:2016-03-16 10:42:05

标签: postgresql recursion

这是我正在采取的课程问题的“解决方案”。但是当我将它复制到我的postgrSQL 9.5.1程序中时,它充满了错误。

CREATE RECURSIVE VIEW Ancestor AS
((SELECT parents.child AS Dec, parents.father AS Anc
FROM windsor.parents)
UNION
(SELECT parents.child AS Dec, parents.mother AS Anc
FROM windsor.parents)
UNION
(SELECT parents.Father AS Anc, Ancestor.Dec As Dec
FROM windsor.parents,Ancestor
WHERE parents.child = Ancestor.Anc)
UNION
(Select parents.mother AS Anc, Ancestor.Dec As Dec
FROM windsor.parents, Ancestor
WHERE parents.child = Ancestor.Anc))

它在行中引发错误:1,带有'AS'的语法错误。在查看了一些声明here并尝试了一些内容后,似乎将其更改为

CREATE RECURSIVE VIEW Ancestor(Anc,Dec) AS 

工作,但现在它在第一次尝试在FROM命令中调用Ancestor时抛出错误。这次的错误是:

Error: rekursiver Verweis auf Anfrage „ancestor“ darf nicht in ihrem nicht-rekursiven Teilausdruck erscheinen
SQL Status:42P19

或用我破碎的英语:

recursive call for "ancestor" mustn't be in a non-recursive part
像我说的那样,这不是我的代码。这是我参加的课程问题的“解决方案”。我正在尝试解决这个问题,但是不要因为这段代码而偏离原来的意图。

欢呼 - 雅各布斯

2 个答案:

答案 0 :(得分:1)

错误是由于在您的视图定义中,您有两个不同的递归子句,而只有一个被允许。

在PostgreSQL manual中,递归视图定义如下:

  

CREATE RECURSIVE VIEW name (columns) AS SELECT ...;   相当于

     

CREATE VIEW name AS WITH RECURSIVE name (columns) AS (SELECT ...) SELECT columns FROM name;

     

必须为递归视图指定视图列列表。

(请注意您使用CREATE RECURSIVE VIEW Ancestor(Anc,Dec)的最后一句 require

然后,在page关于WITH RECURSIVE

  

如果指定了RECURSIVE,则它允许SELECT子查询按名称引用自身。这样的子查询必须具有

形式      

non_recursive_term UNION [ ALL | DISTINCT ] recursive_term

     

其中递归自引用必须出现在UNION的右侧。 每个查询只允许一次递归自引用。(重点是我的)。

因此,您应该仅使用递归子选择来更改查询。

修改

以下是一个可能的解决方案,@ JacobusConradi在下面的评论中对该查询进行了少量修改:

CREATE RECURSIVE VIEW ancestor(anc, dec) AS 
  SELECT  father AS anc, child AS dec
  FROM windsor.parents 
  WHERE father is not null
     UNION 
  SELECT  mother AS anc, child AS dec
  FROM windsor.parents 
  WHERE mother is not null
     UNION 
  SELECT anc, child AS dec
     FROM windsor.parents, ancestor
     WHERE dec = father OR dec = mother

修改涉及:1)消除DISTINCT(我们可以假设child是原始表的主键,并且在任何情况下使用UNION运算符都会自动消除重复项) ,2)添加空值测试,否则在结果中将显示具有ancdec空值的元组。

答案 1 :(得分:0)

正如Renzo指出的那样,你有两个问题需要解决:

  • 只允许一个递归引用
  • 递归引用必须出现在UNION
  • 的最后部分

通过将UNION的最后两个元素组合到子查询中,可以轻松解决第二个限制;而不是A UNION B UNION C UNION D,只需说A UNION B UNION (C UNION D)

至于将递归调用分解为单个引用,这对于common table expression (CTE)非常简单,给你这样的东西:

CREATE RECURSIVE VIEW Ancestor(Anc,Dec) AS
SELECT parents.child AS Dec, parents.father AS Anc
FROM windsor.parents
UNION
SELECT parents.child AS Dec, parents.mother AS Anc
FROM windsor.parents
UNION
(
  WITH cte AS (SELECT * FROM Ancestor)
  SELECT parents.Father AS Anc, cte.Dec As Dec
  FROM windsor.parents, cte
  WHERE parents.child = cte.Anc
  UNION
  SELECT parents.Mother AS Anc, cte.Dec As Dec
  FROM windsor.parents, cte
  WHERE parents.child = cte.Anc
)