Страница 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
Но в используемой версии (не знаю, какая), Оракле не знает этого оператора
Есть идеи?
Добавлено: 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, спасибо.
Практическое решение я могу придумать, это не проблема.
Тот же вью, например - это да.
Просто я - фанат невозможного ))
Просто хотелось бы на заданной схеме получить выборку ОДНИМ запросом.