Программирование >>  Преобразование значений null 

1 ... 49 50 51 [ 52 ] 53 54 55 ... 219


половиная UNION ALL) посредством рекурсии создается список. Чтобы понять, как это происходит, проанализируем некоторые фрагменты решения: сначала третий элемент списка SELECT второго запроса операции UNION ALL:

x.list , e.ename

и затем конструкцию WHERE того же запроса:

where e.deptno = x.deptno and e.empno > x.empno

Сначала в решении проверяется, что все служащие относятся к одному отделу. Затем к каждому служащему, возвращенному верхней частью операции UNION ALL, добавляются имена служащих, которым соответствуют большие значения в столбце EMPNO. Таким образом, гарантируется, что к данному служащему не будет добавлено его собственное имя. Выражение

x.len+1

увеличивает LEN (изначально равное 1) на единицу при обработке каждого последующего служащего. Если это значение равно количеству служащих в отделе:

where len = cnt

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

MySQL

Всю работу выполняет функция GROUP CONCAT. Она осуществляет конкатенацию значений столбца, переданного в нее, в данном случае -ENAME. Эта функция является агрегатной; таким образом, в запросе необходим оператор GROUP BY.

Oracle

Первый шаг к пониманию запроса Oracle - разложить его на части. Отдельно выполняя вложенный запрос (строки 4-10), формируем результирующее множество, включающее следующие данные для каждого служащего: отдел, имя, ранг в соответствующем отделе, получаемый путем сортировки по возрастанию по столбцу EMPNO, и количество служащих в отделе. Например:

select deptno, ename,

row number() over

(partition by deptno order by empno) rn,



from

DEPTNO

ENAME

CLARK

KING

MILLER

SMITH

JONES

SCOTT

ADAMS

FORD

ALLEN

WARD

MARTIN

BLAKE

TURNER

JAMES

Назначение столбца ранга (которому в запросе присвоен псевдоним RN) - обеспечить возможность обхода дерева. Поскольку функция ROW NUMBER формирует список, начиная с единицы, без повторов или пропусков, для того чтобы обратиться к предыдущей (или родительской) строке, необходимо просто вычесть единицу (из текущего значения). Например, предыдущим числом для 3 является 3 минус 1, что равняется 2. В данном контексте, 2 - родитель 3; наблюдать это можно в строке 12. Кроме того, строки

start with rn = 1

connect by prior deptno = deptno

определяют корень для каждого DEPTNO как запись, в которой значение RN равно 1, и создают новый список для каждого нового отдела (при каждом обнаружении в столбце RN значения 1).

Здесь важно подробнее остановиться на части ORDER BY функции ROW NUMBER. Помните, что имена ранжированы по EMPNO и список будет создаваться в соответствующем порядке. Вычисляется количество служащих в отделе (представление под псевдонимом CNT), и это значение обеспечивает, что запрос возвратит список, включающий имена всех служащих отдела. Это необходимо, потому что SYS CONNECT BY PATH создает список путем многократных итераций, и никому не нужен в итоге неполный список. Для иерархических запросов значения псевдостолбца LEVEL (уровень) начинаются с 1 (для запросов, не использующих CONNECT BY, LEVEL равен 0; для версий 10g и более поздних LEVEL доступен только в сочетании с CONNECT BY) и увеличиваются на единицу после добавления каждого служащего отдела (для каждого уровня вложенности иерархии). Поэтому, как только LEVEL становится равным CNT, мы знаем, что достигли последнего EMPNO и получим полный список.

count(*) over (partition by deptno) cnt




Функция SYS CONNECT BY PATH ставит выбранный разделитель (в данном случае запятую) первым элементом списка. Такое поведение может быть нежелательным. В решении данного рецепта вызов функции LTRIM удаляет запятую, стоящую в начале списка.

PostgreSQL

В решении PostgreSQL необходимо заранее знать максимальное число служащих в каждом отделе. Если выполнить отдельно вложенный запрос (строки 11-18), сформируется результирующее множество, включающее (для каждого служащего) отдел, имя с запятой в конце, количество служащих в отделе и количество служащих, значение EMPNO которых меньше, чем у данного служащего:

deptno

emps

cnt pos

--------+---------+-----+-----

SMITH,

5 1

ALLEN,

6 1

WARD,

6 2

JONES,

5 2

MARTIN,

6 3

BLAKE,

6 4

CLARK,

3 1

SCOTT,

5 3

KING,

3 2

TURNER,

6 5

ADAMS,

5 4

JAMES,

6 6

FORD,

5 5

MILLER,

3 3

Скалярный подзапрос, POS (строки 14-15), используется для ранжирования служащих по EMPNO. Например, строка

max(case when pos = 1 then ename else end)

проверяет значение столбца POS на равенство 1. Выражение CASE возвращает имя служащего, если значение POS равно 1, и NULL в противном случае.

Сначала надо создать запрос для определения, какое максимальное число значений может содержаться в одном списке. Исходя из таблицы EMP, наибольшее число служащих в отделе - шесть, поэтому в любом списке может быть не более шести элементов.

Следующий шаг - создание списка. Это делается посредством применения некоторой условной логики (в форме выражения CASE) к строкам, возвращаемым вложенным запросом. Выражений CASE должно быть столько же, сколько существует значений, подлежащих конкатенации.

Если значение POS равно 1, текущее имя добавляется в список. Второе выражение CASE оценивает, равно ли значение POS двум; если да, то



1 ... 49 50 51 [ 52 ] 53 54 55 ... 219

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.224
При копировании материалов приветствуются ссылки.
Яндекс.Метрика