Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции О_о DataBase.doc
Скачиваний:
5
Добавлен:
01.05.2025
Размер:
8.68 Mб
Скачать
    1. Дополнительные возможности формирования запросов

Предложение SELECT, определяющее необходимые запросы, обладает большими возможностями. Кроме возможностей, рассмотренных ранее, здесь рассматриваются следующие:

  • дополнительные возможности группирования;

  • использование общих табличных выражений;

  • использование рекурсивных запросов.

Дополнительные возможности группирования

В списке выбора в предложении SELECT, при использовании агрегатных функций, требующих группирование, могут быть использованы разные формы группирования. Как указывалось ранее, конструкция GROUP BY в предложении SELECT имеет следующий вид:

GROUP BY элемент [, элемент …]

В качестве элемента конструкции GROUP BY, кроме выражения группирования, рассмотренного ранее, могут быть использованы еще группирующее_множество и супер_группы, которые добавляют к рассмотренным ранее правилам записи конструкции GROUP BY некоторые дополнительные возможности.

Группирующее множество

Группирующее множество позволяет указать несколько способов группирования данных в одном предложении SELECT и имеет следующий вид:

GROUPING SETS (элемент_группирования [, … ] ) ,

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

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

Если в конструкции GROUPING SETS указывается несколько элементов группирования, тогда в результат включается несколько групп строк. Каждая группа строк имеет одинаковые значения колонок, определяемых элементом группирования. Не агрегатные колонки из списка выбора SELECT, не включенные в элемент группирования, возвращают значение NULL для каждой строки, сгенерированной для группирующего множества. Это отражает тот факт, что агрегация данных была выполнена без учета значений этих колонок.

Рассмотрим пример. Пусть имеется следующая таблица:

INVOICE

ACode

SId

WId

Qty

A1

S1

W1

120

A1

S1

W2

200

A1

S2

W1

150

A1

S2

W2

100

A2

S1

W1

220

A2

S1

W2

130

A2

S2

W1

250

A2

S2

W2

200

Пусть необходимо сформировать отчет, в котором отражено суммарное количество поставленного товара для каждого вида товара (ACode) и для каждого поставщика (SId).

Результат может быть получен в одном запросе, если использовать группирующее множество:

SELECT ACode, SId, SUM(Qty) AS Total

FROM INVOICE

GROUP BY GROUPING SETS (ACode, SId)

В данном запросе определены два элемента группирования, каждый из которых определяет свои группы строк. В результате выполнения запроса будут сформированы группы строк двух видов: с одинаковым значением атрибута ACode и с одинаковым значением атрибута SId, и для каждой группы будет вычислена агрегатная функция SUM(Qty). Результат отчета может иметь следующий вид:

ACode

SId

Total

-

S1

670

-

S2

700

A1

-

570

A2

-

800

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

SELECT ACode, SId, SUM(Qty) AS Total

FROM INVOICE

GROUP BY GROUPING SETS ((ACode, Sid))

В этом случае в группирующем множестве определен только один элемент группирования, который определяет группы строк с одинаковыми значениями атрибутов ACode и SId. Результат такого запроса может иметь следующий вид:

ACode

SId

Total

A1

S1

320

A1

S2

250

A2

S1

350

A2

S2

450

Видно, что данный запрос эквивалентен следующему:

SELECT ACode, SId, SUM(Qty) AS Total

FROM INVOICE

GROUP BY ACode, SId

Рассмотрим следующий запрос:

SELECT ACode, SId, WId, SUM(Qty) AS Total

FROM INVOICE

GROUP BY GROUPING SETS ((ACode, SId), (ACode, WId))

В нем определены два элемента группирования. Первый элемент определяет группы строк с одинаковыми значениями атрибутов ACode и SId, второй – группы строк с одинаковыми значениями атрибутов ACode и WId. Для каждой группы вычисляется функция SUM(Qty). Результат выполнения запроса может быть следующим:

ACode

SId

WId

Total

A1

-

W1

270

A1

-

W2

300

A2

-

W1

470

A2

-

W2

330

A1

S1

-

320

A1

S2

-

250

A2

S1

-

350

A2

S2

-

450

Следует заметить, что группирующее множество определяет фундамент построения результатов при использовании конструкции GROUP BY. Например, конструкция GROUP BY Col1 эквивалентна конструкции GROUP BY GROUPING SETS((Col1)), а конструкция GROUP BY Col1, Col2, Col3 эквивалентна конструкции GROUP BY GROUPING SETS((Col1, Col2, Col3)).

Супер группа

Супер группа задается одним из следующих способов:

ROLLUP (элемент_группирования [, …])

CUBE (элемент_группирования [, …])

( )

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

Последний элемент (пустые круглые скобки) определяет общий итог, в соответствии с которым весь результат, полученный при выполнении запроса, рассматривается как одна группа строк.

Конструкция ROLLUP расширяет возможности группирования, определяемые конструкцией GROUP BY, включая в результат запроса дополнительные итоговые строки. Итоговые строки получаются в результате создания, на основе списка, указанного в ROLLUP, дополнительных группирующих множеств, путем последовательного исключения последних элементов из списка. Так, если была определена следующая конструкция: ROLLUP(a, b, c), при ее обработке будут созданы следующие группирующие множества: (a, b, c), (a, b), (a), ().

Таким образом, конструкция ROLLUP, в которой указано n элементов, трансформируется в n + 1 группирующее множество.

Следует отметить, что на результат запроса влияет порядок перечисления элементов в конструкции ROLLUP. Так, при обработке конструкции ROLLUP(a, b) будут созданы группирующие множества (a, b), (a), (), тогда как при обработке конструкции ROLLUP(b, a) будут созданы группирующие множества (b, a) (или (a, b)), (b), ().

Рассмотрим пример. Пусть для приведенной выше таблицы выполняется следующий запрос:

SELECT ACode, SId, SUM(Qty) AS Total

FROM INVOICE

GROUP BY ROLLUP (ACode, SId)

ORDER BY ACode, SId

При выполнении данного запроса будут определены несколько групп; в первую группу включаются строки, имеющие одинаковое значение совокупности атрибутов ACode и SId, во вторую группу – строки с одинаковым значением атрибута ACode и третью группу составят все строки таблицы. Результат выполнения запроса может иметь следующий вид:

ACode

SId

Total

A1

S1

320

A1

S2

250

A1

-

570

A2

S1

350

A2

S2

450

A2

-

800

-

-

1370

Конструкция CUBE расширяет возможности группирования, определяемые конструкцией GROUP BY, также включая в результат запроса дополнительные итоговые строки. Однако, в отличие от ROLLUP, дополнительные итоговые строки формируются путем создания всех комбинаций из элементов, указанных в списке CUBE. Так, если была определена следующая конструкция: CUBE(a, b, c), при ее обработке будут созданы следующие группирующие множества: (a, b, c), (a, b), (a, c), (b, c), (a), (b), (c), (). В соответствии с этим, порядок перечисления элементов в конструкции CUBE на результат не влияет.

Таким образом, конструкция CUBE, в которой указано n элементов, трансформируется в 2n группирующих множеств.

Рассмотрим пример. Пусть для приведенной выше таблицы выполняется следующий запрос:

SELECT ACode, SId, SUM(Qty) AS Total

FROM INVOICE

GROUP BY CUBE (ACode, SId)

ORDER BY ACode, SId

При выполнении данного запроса будут определены несколько групп. В первую группу включаются строки, имеющие одинаковое значение совокупности атрибутов ACode и SId, во вторую группу – строки с одинаковым значением атрибута ACode, в третью группу – строки с одинаковым значением атрибута SId, и, наконец, четвертую группу составят все строки таблицы. Результат выполнения запроса может иметь следующий вид:

ACode

SId

Total

A1

S1

320

A1

S2

250

A1

-

570

A2

S1

350

A2

S2

450

A2

-

800

-

S1

670

-

S2

700

-

-

1370

Дополнительные функции

При использовании различных способов группирования в списке SELECT могут быть использованы дополнительные функции – GROUPING и RANK.

Функция GROUPING относится к категории агрегатных функций и имеет следующий синтаксис:

GROUPING(выражение)

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

Функция возвращает целое значение. Результат функции:

1 – значение выражения в строке результата имеет NULL значение, строка была сгенерирована супер группой;

0 – в противном случае.

Например, пусть имеется следующая таблица EMPL:

EMPNO

LASTNAME

SALARY

JOB

EDLEVEL

000120

O’Connel

29250.00

Clerk

14

000100

Spenser

26150.00

Manager

14

000130

Quintana

23800.00

Analyst

16

000280

Schneider

26250.00

Operator

17

000250

Smith

19180.00

Clerk

-

000060

Stern

32250.00

Manager

16

Пусть выполняется следующий запрос:

SELECT EDLEVEL, DECIMAL(AVG(SALARY), 8, 2) AS AVG_Salary

FROM EMPL

GROUP BY ROLLUP(EDLEVEL)

Будут получены следующие результаты:

EDLEVEL

AVG_SALARY

-

26146.66

14

27700.00

16

28025.00

17

26250.00

-

19180.00

В полученных результатах две строки имеют в колонке EDLEVEL пустое значение, и не понятно, какое из них соответствует строке таблицы, а какое – итоговому значению. Использование функции

GROUPING() позволяет ответить на данный вопрос:

SELECT EDLEVEL, GROUPING(EDLEVEL) AS TP,

DECIMAL(AVG(SALARY), 8, 2) AS AVG_Salary

FROM EMPL

GROUP BY ROLLUP(EDLEVEL)

Будут получены следующие результаты:

EDLEVEL

TP

AVG_SALARY

-

1

26146.66

14

0

27700.00

16

0

28025.00

17

0

26250.00

-

0

19180.00

Значение 1 в колонке TP в первой строке указывает, что данная строка сгенерирована супер группой (получена при вычислении итоговых значений при группировании), тогда как третья строка получена в результате обработки строк таблицы.

Функция RANK относится к категории OLAP функций и используется для ранжирования результата.

Функция имеет следующий синтаксис:

RANK () OVER ( [ PARTITION BY колонка ] ORDER BY выражение [ ASC | DESC ] )

Функция ранжирования вычисляет ранг строки в пределах некоторого множества строк.

PARTITION BY указывает, в пределах каких строк следует определять ранг. Если конструкция

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

Строки, не различаемые в пределах данного множества, получают одинаковое значение ранга.

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

Если указывается RANK, ранг строки определяется как 1 плюс количество строк, которые физически предшествуют данной строке. Поэтому, если несколько строк не отличаются друг от друга с позиций упорядоченности, тогда в последовательности значений рангов будут пропуски.

Вместо RANK можно использовать функцию DENSE_RANK, тогда пропусков не будет.

Пример:

SELECT EMPNO, LASTNAME, SALARY,

RANK() OVER(ORDER BY SALARY DESC) AS SALARY_RANK

FROM EMPLOYEE

ORDER BY EMPNO

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

Еще пример:

SELECT WORKDEPT, EMPNO, LASTNAME, EDLEVEL,

DENSE_RANK() OVER(PARTITION BY WORKDEPT

ORDER BY EDLEVEL DESC) AS RANK_EDLEVEL

FROM EMPLOYEE

ORDER BY WORKDEPT, LASTNAME

Здесь для каждого отдела вычисляются свои значения ранга.

Табличные выражения

Ранее рассматривалась возможность использования табличных выражений в конструкции FROM предложения SELECT, например:

SELECT …

FROM ( подзапрос ) AS E

INNER JOIN

( подзапрос ) AS N

ON E.xx = N.xx

В подзапросах, использованных в записи табличных выражений, можно использовать агрегатные функции и группирование.

Наряду с этим, в предложении SELECT могут быть использованы общие табличные выражения. В общем случае, предложение SELECT имеет следующий синтаксис:

WITH

общее_табличное_выражение [, …]

запрос

Правила записи запроса были рассмотрены ранее.

Общее табличное выражение записывается следующим образом:

имя_таблицы [ ( список_колонок ) ] AS ( подзапрос )

Общее табличное выражение позволяет определить таблицу с именем имя_таблицы, которая может быть использована в конструкциях FROM и других следующего за табличным выражением основного запроса. В одной конструкции WITH можно определить несколько табличных выражений; в этом случае имя таблицы может быть указано в любом последующем табличном выражении.

Рассмотрим примеры.

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

С помощью общего табличного выражения данный запрос может быть реализован следующим образом:

WITH

ART(WId, ACode, Qty) AS

(

SELECT WId, ACode, SUM(Qty) FROM INVOICE GROUP BY WId, ACode

),

COM(WId, Qty) AS

(

SELECT WId, SUM(Qty) FROM INVOICE GROUP BY WId

)

SELECT WName, AName, Art.Qty AS SubTotal, Com.Qty AS GrandTotal

FROM WAREHOUSE W, ARTICLE A, ART, COM

WHERE W.WId = ART.WId AND A.ACode = ART.ACode AND W.WId = COM.WId

Или так:

WITH

ART(WId, ACode, Qty) AS

(

SELECT WId, ACode, SUM(Qty) FROM INVOICE GROUP BY WId, ACode

),

COM(WId, Qty) AS

(

SELECT WId, SUM(Qty) FROM ART GROUP BY WId

)

SELECT WName, AName, ART.Qty AS SubTotal, COM.Qty AS GrandTotal

FROM WAREHOUSE W, ARTICLE A, ART, COM

WHERE W.WId = ART.WId AND A.ACode = ART.ACode AND W.WId = COM.WId

2. Вернемся к задаче H1 из раздела 4.6: найти имена поставщиков, поставляющих максимальное суммарное количество товара. В рассмотренном ранее примере использовалось представление.

Использование табличного выражения в конструкции FROM не позволяет получить требуемый результат, так как к этому табличному выражению приходится ссылаться из подзапроса, используемого в конструкции WHERE основного запроса, что недопустимо:

SELECT SName

FROM Salor S,

(SELECT SId, SUM(Qty) FROM Invoice GROUP BY SId) AS V1(SId, Qty)

WHERE S.SId = V1.SId AND

V1.Qty = (SELECT MAX(Qty) FROM V1) –- здесь в подзапросе имя V1 не определено

Проблему решает общее табличное выражение: определяемая им таблица может быть использована и в подзапросе:

WITH

V1(SId, Qty) AS

(

SELECT SId, SUM(Qty) FROM INVOICE GROUP BY SId

)

SELECT SName

FROM SALOR S, V1

WHERE S.SId = V1.SId AND V1.Qty = (SELECT MAX(Qty) FROM V1)

Рекурсивное табличное выражение

Подзапросы, использованные в определении общего табличного выражения, могут ссылаться на это же табличное выражение; в этом случае общее табличное выражение определено как рекурсивное общее табличное выражение.

Рекурсивное общее табличное выражение состоит из двух запросов, объединенных операцией

UNION ALL. Первый запрос в выражении определяется как инициализирующий и не должен ссылаться на это же табличное выражение; второй запрос определяется как итерационный (повторяющийся) и содержит ссылку на это же табличное выражение:

WITH имя_таблицы (список_колонок) AS

(

инициализирующий_запрос

UNION ALL

итерационный_запрос

)

основной_запрос

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

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

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

Рассмотрим следующий пример.

Пусть определено некоторое отношение КОМПОНЕНТ, для которого определена рекурсивная связь с этим же отношением: каждый компонент, представляя некоторый агрегат, состоит из нескольких (0 или более) компонентов; компонент, являясь частью, входит в несколько (0 или более) других компонентов.

Такое отношение может быть представлено таблицей PARTLIST, имеющей следующие колонки: Part для представления компонента – агрегата, Subpart для представления компонента – части и Quantity для указания того, в каком количестве компонент-часть включен в компонент-агрегат:

CREATE TABLE PARTLIST (

Part VARCHAR(8),

Subpart VARCHAR(8),

Quantity INTEGER

);

Предположим, что таблица PARTLIST имеет следующий вид:

Part

Subpart

Quantity

00

01

5

00

05

3

01

02

2

01

03

3

01

04

4

01

06

3

02

05

7

02

06

6

03

07

6

04

08

10

04

09

11

05

10

10

05

11

10

06

12

10

06

13

10

07

14

8

07

12

8

Пример 1. Написать запрос, позволяющий получить, какие компоненты необходимы для построения некоторого заданного компонента, например, компонента с номером ’01’. Полученный список должен включать все компоненты, входящие в состав заданного (подкомпоненты первого уровня); компоненты, входящие в состав подкомпонентов первого уровня, и т.д. При этом, если некоторый компонент используется несколько раз (как часть разных компонентов), он должен быть включен только один раз.

WITH RPL (Part, Subpart, Quantity) AS

(

SELECT ROOT.Part, ROOT.Subpart, ROOT.Quantity

FROM PARTLIST ROOT

WHERE ROOT.Part = '01'

UNION ALL

SELECT CHILD.Part, CHILD.Subpart, CHILD.Quantity

FROM RPL PARENT, PARTLIST CHILD

WHERE PARENT.Subpart = CHILD.Part

)

SELECT DISTINCT Part, Subpart, Quantity

FROM RPL

ORDER BY Part, Subpart, Quantity;

Приведенный запрос включает общее табличное выражение, названное RPL (Recursive PARTLIST), которое определяет рекурсивную часть запроса. Оно иллюстрирует основные элементы рекурсивного общего табличного выражения. Первый операнд (запрос) операции UNION, определяемый как инициализирующий запрос, позволяет получить компоненты, подчиненные непосредственно компоненту с номером ’01’. В конструкции FROM этого запроса используется исходная таблица и никогда не используется это же табличное выражение (RPL в данном примере). Результат первого запроса записывается в таблицу общего табличного выражения RPL, и RPL будет иметь следующий вид:

Номер строки

Part

Subpart

Quantity

1

01

02

2

2

01

03

3

3

01

04

4

4

01

06

3

Как и в данном примере, всегда должна использоваться операция UNION ALL. Второй операнд (запрос) операции UNION использует RPL для вычисления подкомпонентов для подкомпонентов, указывая в конструкции FROM соединение таблицы общего табличного выражения RPL (PARENT) по атрибуту Subpart и исходной таблицы (CHILD) по атрибуту Part. Результат также записывается в RPL. По мере появления новых строк в RPL они будут использоваться в запросе, определенном во втором операнде UNION.

После первой итерации в табличное выражение RPL будут добавлены строки с 5-й по 11-ю, и просмотр табличного выражения RPL закончится на 4-й строке:

Номер строки

Part

Subpart

Quantity

1

01

02

2

2

01

03

3

3

01

04

4

4

01

06

3

5

02

05

7

6

02

06

6

7

03

07

6

8

04

08

10

9

04

09

11

10

06

12

10

11

06

13

10

На второй итерации обработка RPL продолжится с 5-й строки; в результате в RPL будут добавлены строки с 12-й по 17-ю, и просмотр табличного выражения RPL закончится на 11-й строке:

Номер строки

Part

Subpart

Quantity

1

01

02

2

2

01

03

3

3

01

04

4

4

01

06

3

5

02

05

7

6

02

06

6

7

03

07

6

8

04

08

10

9

04

09

11

10

06

12

10

11

06

13

10

12

05

10

10

13

05

11

10

14

06

12

10

15

06

13

10

16

07

14

8

17

07

12

8

На следующей итерации обработка RPL продолжится с 12-й строки. В строках с 12-й по 17-ю в колонке Subpart RPL указаны значения, которые отсутствуют в колонке Part основной таблицы, поэтому новые строки в RPL не заносятся; когда все строки RPL будут просмотрены (обработаны), выполнение запроса завершится.

В полученном результате можно заметить, что, например, строка <06, 12, 10> появилась дважды: один раз в результате обработки связи 01 – 06, 06 – 12, второй раз – в результате обработки связи 01 – 02, 02 – 06, 06 – 12. Фраза SELECT DISTINCT в основном запросе гарантирует, что одни и те же значения Part/Subpart не будут выведены более одного раза.

В результате выполнения приведенного запроса будут получены следующие данные:

Part

Subpart

Quantity

01

02

2

01

03

3

01

04

4

01

06

3

02

05

7

02

06

6

03

07

6

04

08

10

04

09

11

05

10

10

05

11

10

06

12

10

06

13

10

07

12

8

07

14

8

Пример 2. Написать запрос, позволяющий получить общее количество каждого компонента, входящего в состав некоторого заданного компонента, например, компонента с номером ’01’.

Главное отличие от примера 1 заключается в том, что здесь необходимо использовать агрегатную функцию для суммирования количества компонентов. Так, например, компонент ’02’ включает 6 экземпляров компонента ’06’. Если компонент ’01’ включает 2 экземпляра компонента ’02’, значит, для построения компонента ’01’, в общем случае, потребуется 2*6 = 12 экземпляров компонента ’06’.

WITH RPL (Part, Subpart, Quantity) AS

(

SELECT ROOT.Part, ROOT.Subpart, ROOT.Quantity

FROM PARTLIST ROOT

WHERE ROOT.Part = '01'

UNION ALL

SELECT PARENT.Part, CHILD.Subpart, PARENT.Quantity *CHILD.Quantity

FROM RPL PARENT, PARTLIST CHILD

WHERE PARENT.Subpart = CHILD.Part

)

SELECT Part, Subpart, SUM(Quantity) AS "Total QTY Used"

FROM RPL

GROUP BY Part, Subpart

ORDER BY Part, Subpart

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

В результате выполнения приведенного запроса будут получены следующие данные:

Part

Subpart

Total QTY Used

01

02

2

01

03

3

01

04

4

01

05

14

01

06

15

01

07

18

01

08

40

01

09

44

01

10

140

01

11

140

01

12

294

01

13

150

01

14 

144

Так, подкомпонент (Subpart) типа ’06’ входит в состав компонента ’01’ непосредственно в количестве 3 экземпляров, а также через компонент ’02’ в количестве 2 * 6 = 12 экземпляров; в общем случае, в компонент ’01’ входит 15 экземпляров подкомпонента ’06’.

Пример 3. В некоторых случаях нет необходимости обрабатывать данные на всю глубину рекурсии; достаточно ограничиться несколькими первыми уровнями. Например, требуется получить только первые два уровня вложенности компонентов в компонент с номером ’01’. Другими словами, в отчет необходимо включить значение, определяющее глубину рекурсии. Это достигается за счет включения во второй запрос дополнительной вычисляемой колонки вида col + 1 (увеличение значения колонки на 1 при каждой следующей итерации); в инициализирующем запросе в соответствующей колонке должно быть указано начальное значение. Эта колонка может использоваться во втором запросе в конструкции WHERE для ограничения глубины рекурсии.

WITH RPL (Level, Part, Subpart, Quantity) AS

(

SELECT 1, ROOT.Part, ROOT.Subpart, ROOT.Quantity

FROM PARTLIST ROOT

WHERE ROOT.Part = '01'

UNION ALL

SELECT PARENT.Level + 1, CHILD.Part, CHILD.Subpart, CHILD.Quantity

FROM RPL PARENT, PARTLIST CHILD

WHERE PARENT.Subpart = CHILD.Part AND PARENT.Level < 2

)

SELECT Part, Level, Subpart, Quantity

FROM RPL;

Приведенный запрос аналогичен запросу примера 1. В данном запросе в общее табличное выражение добавлена колонка Level для определения глубины рекурсии. В инициализирующем запросе в данную колонку записывается значение 1. Во втором запросе значение колонки Level, считываемое из таблицы общего табличного выражения RPL (PARENT), увеличивается на 1. Для управления глубиной рекурсии во второй запрос в конструкцию WHERE добавлено условие Level < 2. Это условие гарантирует, что будет рассмотрено только два уровня вложенности компонентов.

В результате выполнения приведенного запроса будут получены следующие данные:

Part

Level

Subpart

Quantity

01

1

02

2

01

1

03

3

01

1

04

4

01

1

06

3

02

2

05

7

02

2

06

6

03

2

07

6

04

2

08

10

04

2

09

11

06

2

12

10

06

2

13

10