Страница 1 из 2

Oracle, рекурсивные запросы(или как ето делается)

Добавлено: 12 май 2005, 20:29
Oscar

Код: Выделить всё

CREATE TABLE direktora (
	id INTEGER PRIMARY KEY,
	direktor INTEGER REFERENCES direktora
	);
INSERT INTO direktora VALUES (4,4);
INSERT INTO direktora VALUES (3,4);
INSERT INTO direktora VALUES (2,3);
INSERT INTO direktora VALUES (1,2);
INSERT INTO direktora VALUES (10,10);
INSERT INTO direktora VALUES (8,10);
INSERT INTO direktora VALUES (7,8 );
INSERT INTO direktora VALUES (9,7);
INSERT INTO direktora VALUES (6,9);
INSERT INTO direktora VALUES (5,6);
SELECT * FROM direktora ORDER BY id;

Код: Выделить всё

        ID   DIREKTOR
---------- ----------
         1          2
         2          3
         3          4
         4          4
         5          6
         6          9
         7          8
         8         10
         9          7
        10         10
id - ID человека
direktor - ID его начальника

Kак получить список всех начальников человека с id = 9 ?


Вообще-то, конечно, интересует общий случай.


Пробовал так:

Код: Выделить всё

SELECT DISTINCT d1.id, d1.direktor
FROM direktora d1,
     direktora d2
WHERE (d1.direktor = d2.id OR d2.direktor = d1.id)
  AND (d1.direktor != d1.id AND d2.direktor != d2.id)
ORDER BY d1.id;
Но как к нему привязать, с какого id начинать?

интересует чистое SQL решение, без PL и Co.

нашел вот еще:

Код: Выделить всё

SELECT id, direktor FROM direktora
START WITH id = 9
CONNECT BY PRIOR id = direktor;
но оно строет дерево вниз от точки начала, а не вверх

Добавлено: 13 май 2005, 12:39
Absurd
Паапробуй паменять палярность...
CONNECT BY PRIOR director = id;

Добавлено: 13 май 2005, 14:10
Oscar
Absurd, Пробовал ))
Не помогло
Пишет: user data in loop, или что-то в этом роде.

да и PRIOR - я подозреваю, что это праймери ключ, которым ID и является.

Добавлено: 13 май 2005, 14:40
Absurd
Нет это вроде порядок- как спускаться. От id к director или от director к id

Добавлено: 13 май 2005, 14:44
Absurd
Иерархию через вложенные множества я даже на MySQL делал. Да, для нее нужен join таблицы самой на себя. Но делается это не так.

Добавлено: 13 май 2005, 14:59
Absurd
Кстати, понял от чего выскакивает ошибка. У директора 10 директор -10, поэтому получается бесконечная рекурсия в недрах Оракла.

Добавлено: 13 май 2005, 15:17
Oscar
Absurd,
да, наверное так.
а как же её остановить?

Дело в том, что таблица Директора связана с таблицей Персонал, обоими колонками по ID персонала.
Потому поле директор в таблице Директора нельзя NULL сделать.


----

Код: Выделить всё

UPDATE direktora SET direktor = NULL WHERE id=direktor;
SELECT id, direktor FROM direktora
START WITH id = 9
CONNECT BY PRIOR direktor = id;
Да, это возвращает именно то, что нужно!
Вот только ... Это не одна таблица на самом деле, и всё взаимосвязано, потому нельзя менять структуру...

Может всё же есть какой-то способ как-то ограничить рекурсию по
WHERE id!=direktor ?....

Мою проблему решил бы оператор NOCYCLE

Код: Выделить всё

CONNECT BY NOCYCLE PRIOR direktor = id
Но в используемой версии (не знаю, какая), Оракле не знает этого оператора :(

Есть идеи?

Добавлено: 14 май 2005, 11:27
Absurd
В общем-то если у человека нет вышестоящего директора, то соответствующее поле дожно быть null. Это вполне естественно.

Это естественно даже не для баз данных, а для просто структур данных. В связанном списке последний элемент имеет указатель на следующий равный null. В дереве корневой элемент имеет указатель на предка равный null.

Если поле - foreign key не имеет primary key, которому его нужно сопоставить, то оно всегда делается null. При необходимости оно может быть вытащено через left (или right) join.
Если в базе как-то неверно расставлены констрейнты, то обратись к архитектору.
Если имеем унаследованный код, авторы которого не знали ничего про внешние join'ы , который очень болшой и который нельзя трогать, то тогда можно только посочувствовать.

Добавлено: 14 май 2005, 14:01
Absurd
На худой конец можешь вьюху сделать

create view direktora1 as SELECT id, (case when direktor = id then null else direktor end) as direktor FROM direktora;

Добавлено: 15 май 2005, 00:09
Oscar
Absurd, спасибо.

Практическое решение я могу придумать, это не проблема.
Тот же вью, например - это да.

Просто я - фанат невозможного ))
Просто хотелось бы на заданной схеме получить выборку ОДНИМ запросом.