2016-03-16 63 views
1

这是我正在学习的课程的“解决方案”。但是当我将它复制到我的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命令。错误这段时间是:

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 

就像我说的,这不是我的代码。对于我参加的课程提出的问题,这是一个“解决方案”。我正在尝试解决这个问题,但是不想从这个代码的原意上移开得太远。

欢呼声 - 雅克布斯

回答

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)

然后,在pageWITH RECURSIVE

如果指定递归的,它允许一个SELECT子查询引用本身就是名字。这样的子查询必须具有其中递归自引用必须出现在UNION的右手侧的形式

non_recursive_term UNION [ ALL | DISTINCT ] recursive_term

每个查询只允许一个递归自引用。(重点是我的)。

所以,你应该改变你的查询,只使用递归子查询。

编辑

这里是一个可能的解决方案,通过在@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是原始表的主键,并且在任何情况下使用运算符自动消除重复),2)为空值添加测试,否则在结果中会出现带有空值的元组值对于ancdec

+0

首先感谢您的回答:)从什么我从你的回答中了解到,是第一位:(安科,十二月)是必需的,这对我来说是完全合理的。第二个对我来说最初没有意义,“只有在工会电话会议之后递归”,但我想我现在明白了。问题仅在第三个联合区块中。我将如何解决这个问题,尤其是在“一次呼叫限制”方面? – PlatinTato

+0

为了回答你的问题,我应该知道'父母'表,从你的角度来看,我不清楚。这是'(孩子,父亲,母亲)'吗?那么,'name'是什么?或者(名字,孩子,父亲,母亲)?然后,我不会看到什么是孩子。 – Renzo

+0

我现在看到另一个我在问这个问题时似乎忽略了的错误。它是(小孩,父亲,母亲),名字也应该是小孩。设计这个课程的人在他的所有Powerpoint节目中都命名为“名字”,但他分享的文件名为“孩子”。我在问题中编辑。 – PlatinTato

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 
) 
+0

我很感谢你的回答,即使我已经用Renzo告诉我的解决了它。我很好奇,因为递归调用并不是最后一次“联合”之后,还是因为最后一个联合与另一个不在同一级别?我刚刚执行它,它运作良好,但我不明白为什么它的工作与上面的语法要求 – PlatinTato

+0

@Jacobus:是的,这是因为它是嵌套的;要求是最后一个顶级联合包含递归术语。 –

+0

感谢赞赏:) – PlatinTato