Рекурсивные запросы в Oracle Фёдоров Р.К. Рекурсивные запросы • Рекурсивные запросы используются для обращения к иерархически связанным данным. • create table test_table ( id number(6), pid number(6), title varchar2(256) ); test_table Иерархическая организация данных • Большинство современных СУБД (Система Управления Базами Данных) — реляционные, т.е. представляют данные в виде двумерной таблицы, в которой есть строки (записи) и столбцы (поля записей). Но на практике мы часто сталкиваемся с иной организацией данных, а именно иерархической. Примеры • Список файлов на компьютере: все они организованы в виде дерева. • Книги в библиотеке: Библиотека->Зал->Шкаф>Полка->Книга. • Статьи на сайте: Сайт->Раздел->Подраздел->Статья. Можно разделить все на отдельные таблицы: таблица для хранения списка библиотек, другая таблица для списка залов, третья для шкафов и т.д. Но если заранее не известна глубина вложенности или эта вложенность может меняться, тут уж от иерархии никак не отмашешься. • Данные, имеющие иерархическую структуру, очень плохо представляются в реляционной модели. В стандарте SQL-92 нет средств для их обработки. • В Oracle иерархические запросы появились в 8-ой версии, задолго до появления стандарта. Поэтому до сих пор используется совсем другой синтаксис. START WITH • Необязательный оператор START WITH говорит Ораклу с чего начинать рекурсию, т.е. какая строка (или строки) будет корневой. Условие может быть практически любым, можно даже использовать функции или внутренние запросы: pid is null, или id = 1, или даже substr(title, 1, 1) = ‘Р’. CONNECT BY • Задает отношение между родительскими и дочерними строками в иерархии. Отношение задается условием, это может быть любое сравнение, но какая-то его часть должна содержать ключевое слово PRIOR, относящееся к родительской строке. • Каждая дочерняя строка должна удовлетворять условию в фразе CONNECT BY по отношению к одной из корневых строк. PRIOR • Для задания отношения родитель – ребенок нужно использовать специальный оператор, который называется PRIOR. С его помощью можно написать правило pid = PRIOR id. Выбрать фамилии всех прямых начальников сотрудника по фамилии ADAMS • SELECT id, last_name, manager_id FROM employee CONNECT BY PRIOR manager_id=id START WITH last_name= 'ADAMS' Псевдостолбец LEVEL • Возвращает уровень записи по отношению к корневой. Так, 1-ая запись будет иметь уровень 1, ее потомки уровень 2, потомки потомков — 3 и т.д. Сортировка в пределах уровня иерархии • ORDER SIBLINGS BY <выражение> • Пример • SELECT lpad(' ', 3*level)||title as Tree FROM test_table START WITH pid is null CONNECT BY PRIOR id = pid ORDER SIBLINGS BY title; Вывод пути • SYS_CONNECT_BY_PATH() SELECT SYS_CONNECT_BY_PATH(title, '/') as Path FROM test_table WHERE id=9 START WITH pid is null CONNECT BY PRIOR id = pid; Псевдостолбец CONNECT_BY_ISLEAF • В этом псевдостолбце напротив каждой строки проставляется 0 или 1. Если есть потомки – проставится 0. Если потомков нет, такой узел в дереве называется “листом”, тогда и значение в поле CONNECT_BY_ISLEAF будет равно 1. Псевдостолбец CONNECT_BY_ROOT • Ссылается на корневую запись, т.е. на самую первую в выборке. SELECT id, pid, title, level, CONNECT_BY_ISLEAF as IsLeaf, PRIOR title as Parent, CONNECT_BY_ROOT title as Root FROM test_table START WITH pid is null CONNECT BY PRIOR id = pid ORDER SIBLINGS BY title; Результат Используемые материалы • http://habrahabr.ru/post/43955/