
- •Урок 12. РекурсивныйSql
- •Древовидные структуры
- •Стандартное представление и манипулирование деревьями в sql
- •Рекурсивные запросы в Oracle
- •Фраза startwith
- •Фраза connectby
- •Использование псевдостолбца level
- •Задание условия
- •Условие на глубину иерархической структуры
- •Упорядочение строк с помощью фразы order by
- •Подзапрос в startwith
- •Рекурсивные запросы в стандарте sql
- •Определение повторяющихся подзапросов
- •Рекурсивное выполнение запросов
- •Примеры рекурсивных запросов: рейсовые полеты
- •Рекурсия с накоплением
- •Рекурсия и соединение таблиц
- •Отрицание и группирование в рекурсии
- •Примеры рекурсивных запросов: комплектация изделий
- •Вычисление промежуточных количественных характеристик
- •Итоговые количественные вычисления
- •Игнорирование фиктивных изделий
- •В каких агрегатах используется деталь?
- •Parts explosion excluding base parts (Testing For Leaf Nodes In a Parts Explosion)
- •Характеристики поиска
- •Фиксация наличия циклов
- •Направление поиска
- •Более сложная структура рекурсивного запроса
- •Рекурсивные представления
- •Различные виды рекурсии
- •Прямая и взаимная рекурсия
- •Линейная и нелинейная рекурсия
- •Подведение итогов
- •Самостоятельная работа
Фраза connectby
Фраза CONNECT BYпозволяет специфицировать связь между столбцами, формирующую иерархическое дерево. Она содержит условие, которое определяет древовидную связь. Условие может быть любым допустимым условием языка SQL, однако левая или правая часть условия должна содержать операторPRIOR, который указывает какая из строк выступает в качестве родительской. То есть условие в этой фразе должно иметь один из следующих видов:
PRIOR выражение_1 оператор_сравнения выражение_2
выражение_1 оператор-сравнения PRIOR выражение_2
Для нахождения всех дочерних строк для родительской строки сначала вычисляется выражение, находящееся со стороны оператора PRIOR, а затем вычисляет второе выражение для всех строк таблицы. Те строки, для которых второе выражение оказывается истинным, рассматриваются как дочерние для текущей родительской строки. ФразаCONNECT BYможет содержать другие условие для дальнейшей фильтрации выбираемых строк. ФразаCONNECT BYне может содержать подзапрос.
Если вычисление дерева приводит к «зацикливанию», то это рассматривается как ошибочная ситуация. Зацикливание происходит в том случае, когда строка оказывается одновременно родительской (непосредственно или через несколько уровней) и дочерней (непосредственно или через несколько уровней) другой строки.
В приводимом ниже примере фраза CONNECT BYопределяет древовидную связь, в которой значение столбцаTchPKродительской строки должно быть равно значению столбцаChiefдочерней строки:
CONNECTBYPRIORTchPK=Chief
В следующем примере фразы CONNECT BYоператорPRIORприменяется только к значению столбцаTchPK. В связи с этим значениеTchPKвычисляется для родительской строки, а значенияChiefиSalaryдля дочерних:
CONNECT BY PRIOR TchPK = Chief AND Salary > 1000
Содержательно это следует трактовать следующим образом: соединять строки таким образом, чтобы TchPKродительской строки был равенChiefдочерней строки и у дочерней строки значение зарплаты было бы больше 1000.
Использование псевдостолбца level
В Oracle существует такое понятие как псевдостолбец. Это означает следующее: всякий раз, когда вы создаете таблицу базы данных и/или когда формируется таблица в результате вычисления запроса, Oracle автоматически приписывает к такой таблице дополнительные столбцы, значения которых ведутся самой системой. Что именно записывается в таких столбцы зависит от их семантики. Пользователь не может записать в такой столбец свое значение, но в любой момент времени может обратиться к его значению.
При выполнении рекурсивного предложения SELECTстановится доступным псевдостолбец под именемLEVEL. Для каждой строки, формируемой рекурсивным запросом, псевдостолбецLEVELвозвращает значение 1 для корневой вершины, значение 2 для всех дочерних вершин корневой вершины, и т.д. На рис. 10.4 показывается древовидная структура таблицы с ее значениями столбцаLEVEL.
Рис.10.4. Древовидная структура таблицы с указанием уровней.
Рассмотрим пример вычисления рекурсивного запроса с использованием уровней. В приводимом ниже запросе производится поиск по каждому преподавателю его подчиненных, причем результат выдается согласно иерархической упорядоченности подчинения. Корневой является строка, соответствующая преподавателю, у которого столбец ChiefравенNULL. Дочерние строки определяются таким образом, что их значения поляChiefравны значению поляTchPKродительской строки.
SELECTLPAD(' ',2*(LEVEL-1)) ||NameAS"Фамилия",TchPKAS"Номер преп.",ChiefAS"Номер руков.",PostAS"Должность преп."FROM TEACHER START WITH Chief IS NULL CONNECT BY PRIOR TchPK = Chief;
Фамилия Номер преп. Номер руков. Должность преп. ----------------- ----------- ------------ --------------- Сидоров 16 профессор Радишевский 4 16 доцент Хоменко 2 4 преподаватель Витковский 1 2 ассистент Воробьев 3 4 ассистент Кузнецов 5 4 преподаватель Марченко 9 5 ассистент Заплатинский 6 16 доцент Козлитин 8 6 ассистент Лебедь 7 16 доцент Недоводеев 11 7 преподаватель Резник 10 16 профессор Ахромеев 13 профессор Наумов 14 доцент Дараганов 15 преподаватель
15 строк выбрано.
Функция LPADприводит к формированию пробелов, кратных уровню, на котором расположена строка. Такие пробелы, сцепленные с помощью оператора конкатенации (||) с именами служащих, приводят к отступу имен согласно подчинению преподавателей.
Обратите внимание, что корневой сегмент имеет значение NULLдляChief. Если бы для указания этого корня было бы принято решение указать 16 в качестве значения столбцаChief(таким образом мы как бы указали, что он является руководителем над самим собой), то рекурсивный запрос не был бы отработан, так как представленная таким образом иерархическая структура имела бы цикл. Как видим из ответа, у нас 4 преподавателя на верхнем уровне.