2016-03-16 2 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))

Затем в 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) добавление теста для нулевых значений, иначе в результате появятся кортежи с нулевым значением значения для anc или dec.

+0

Прежде всего спасибо за ответ :) от того, что я понял из вашего ответа, это то, что 1-й: требуется (Anc, Dec), что имеет для меня полный смысл. Второй из них не имел смысла для меня изначально, с «рекурсивным только ПОСЛЕ профсоюзного вызова», но я думаю, что я понял это сейчас. Проблема только в третьем блоке объединения. как бы я обошел это, особенно с «одним лимитом»? – PlatinTato

+0

Чтобы ответить на ваш вопрос, я должен знать таблицу «родителей», которая, с вашего взгляда, мне не понятна. Это '(ребенок, отец, мать)'? Затем, что такое 'имя'? Или это («имя, ребенок, отец, мать»)? Тогда я не понимаю, что такое ребенок. – Renzo

+0

Теперь я вижу другую ошибку, которую я, кажется, забыл, задавая этот вопрос. это (ребенок, отец, мать), и имя должно было быть ребенком. парень, который разработал этот курс, назвал его «имя» во всем своем шоу Powerpoint, но файлы, которые он поделил, назвали «child». я редактировал в вопросе. – 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

Я благодарен за ваш ответ, даже если я уже решил его с тем, что сказал мне Ренцо. Мне любопытно, потому что ваш рекурсивный звонок не после последнего «союза», или это потому, что последний союз не находится на том же уровне, что и другой? Я просто выполнил его, и он работает хорошо, но я не понимаю, почему он работает с требованиями синтаксиса выше. – PlatinTato

+0

@Jacobus: Да, это потому, что он вложен; требование состоит в том, что последний союз * верхнего уровня * содержит рекурсивный член. –

+0

благодарите за это :) – PlatinTato

Смежные вопросы