Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
11
Добавлен:
15.01.2021
Размер:
10.35 Mб
Скачать

Пример 46: формирование и анализ иерархических структур

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

MS SQL Решение 7.1.1.a (пример использования функции)

1SELECT * FROM GET_ALL_CHILDREN(2, 'STRING');

2SELECT * FROM GET_ALL_CHILDREN(2, 'TABLE');

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

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

Воснове решения лежит т.н. рекурсивное общее табличное выражение40. Рассмотрим его отдельно.

MS SQL Решение 7.1.1.a (рекурсивное общее табличное выражение)

1WITH [tree] ([sp_id], [sp_parent])

2AS

3(

4SELECT [sp_id],

5[sp_parent]

6

 

FROM

[site_pages]

7

 

WHERE

[sp_id] = {родительская_вершина}

8UNION ALL

9SELECT [inner].[sp_id],

10[inner].[sp_parent]

11

 

FROM [site_pages] AS [inner]

12JOIN [tree]

13ON [inner].[sp_parent] = [tree].[sp_id]

14)

15SELECT [sp_id]

16

 

FROM

[tree]

17

 

WHERE

[sp_id] != {родительская_вершина}

 

 

 

 

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

в первой части (строки 4-7) происходит выборка родительской записи (для которой мы будем искать дочерние);

во второй части (строки 8-13) происходит рекурсивное обращение к результату выполнения общего табличного выражения, что и позволяет нам получить всё поддерево заданной вершины.

Поскольку первая часть (до оператора UNION) является обязательной, а по

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

Полученное рекурсивно общее табличное выражение мы разместили в строках 10-27 кода функции, обеспечив вставку его результатов (строка 24) в результирующую таблицу, которую возвращает функция.

В строках 31-50 кода функции находится то же самое рекурсивное общее табличное выражение, но при выборке результатов его выполнения мы применяем приём, подробно описанный в решении{72} задачи 2.2.2.a{71} для эмуляции функции

GROUP_CONCAT MySQL.

40 https://msdn.microsoft.com/en-us/library/ms175972%28v=sql.110%29.aspx

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 480/545

Пример 46: формирование и анализ иерархических структур

Переходим к Oracle. Здесь решение будет практически идентичным решению для MS SQL Server. Единственное отличие — в способе возврата таблицы из функции (мы рассматривали этот вопрос ранее, см. решение{355} задачи 5.1.1.b{352}). И здесь мы также вынуждены эмулировать поведение функции MySQL GROUP_CONCAT через использование функции Oracle LISTAGG (см. решение{72} задачи

2.2.2.a{71}).

Oracle

Решение 7.1.1.a (код функции)

1CREATE TYPE "tree_node" AS OBJECT("id" VARCHAR(32767));

2/

3

4CREATE TYPE "nodes_collection" AS TABLE OF "tree_node";

5/

6

 

 

7

 

CREATE OR REPLACE FUNCTION GET_ALL_CHILDREN(parent_id NUMBER,

8

 

function_mode VARCHAR)

9RETURN "nodes_collection"

10AS

11result_collection "nodes_collection";

12BEGIN

13IF (function_mode = 'TABLE')

14THEN

15WITH "tree" ("sp_id", "sp_parent")

16AS

17(

18SELECT "sp_id",

19

 

 

"sp_parent"

20

 

FROM

"site_pages"

21WHERE "sp_id" = parent_id

22UNION ALL

23SELECT "inner"."sp_id",

24

 

 

"inner"."sp_parent"

25

 

FROM

"site_pages" "inner"

26

 

 

JOIN

"tree"

27

 

 

ON

"inner"."sp_parent" = "tree"."sp_id"

 

 

 

 

 

28)

29SELECT "tree_node"(TO_CHAR("sp_id"))

30BULK COLLECT INTO result_collection

31 FROM "tree"

32WHERE "sp_id" != parent_id;

33ELSE

34WITH "tree" ("sp_id", "sp_parent")

35AS

36(

37SELECT "sp_id",

38

 

 

"sp_parent"

39

 

FROM

"site_pages"

40WHERE "sp_id" = parent_id

41UNION ALL

42SELECT "inner"."sp_id",

43

 

 

"inner"."sp_parent"

44

 

FROM

"site_pages" "inner"

45

 

 

JOIN

"tree"

46

 

 

ON

"inner"."sp_parent" = "tree"."sp_id"

47)

48SELECT "tree_node"(LISTAGG(TO_CHAR("sp_id"), ',' )

49

 

 

WITHIN GROUP (ORDER BY "sp_id"))

50

 

BULK

COLLECT INTO result_collection

51

 

FROM

"tree"

52WHERE "sp_id" != parent_id;

53END IF;

54RETURN result_collection;

55END;

56/

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 481/545

Пример 46: формирование и анализ иерархических структур

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

Oracle Решение 7.1.1.a (пример использования функции)

1SELECT *

2FROM TABLE(CAST(GET_ALL_CHILDREN(2, 'STRING') AS "nodes_collection"));

3

4SELECT *

5FROM TABLE(CAST(GET_ALL_CHILDREN(2, 'TABLE') AS "nodes_collection"));

На этом решение данной задачи завершено.

Решение 7.1.1.b{475}.

Легко заметить, что решение этой задачи основано на рассуждениях, представленных в решении{476} задачи 7.1.1.a{475}. Если допустить, что соответствующие функции у нас уже есть, код для всех трёх СУБД будет выглядеть так.

MySQL

Решение 7.1.1.b (использованием функции GET_ALL_CHILDREN из решения 7.1.1.a)

1SELECT `sp_id`,

2`sp_name`

 

3

 

FROM

`site_pages`

 

4

 

WHERE

`sp_id` = {родительская_вершина}

 

5

 

 

 

OR FIND_IN_SET(`sp_id`, GET_ALL_CHILDREN({родительская_вершина}))

 

 

 

 

 

MS SQL

 

Решение 7.1.1.b (использованием функции GET_ALL_CHILDREN из решения 7.1.1.a)

1SELECT [sp_id],

2[sp_name]

3 FROM [site_pages]

4WHERE [sp_id] = {родительская_вершина}

5OR [sp_id] IN

 

6

 

 

(SELECT [id]

 

7

 

 

FROM GET_ALL_CHILDREN({родительская_вершина}, 'TABLE'))

 

 

 

 

 

Oracle

 

Решение 7.1.1.b (использованием функции GET_ALL_CHILDREN из решения 7.1.1.a)

1SELECT "sp_id",

2"sp_name"

3 FROM "site_pages"

4WHERE "sp_id" = {родительская_вершина}

5OR "sp_id" IN

6

 

(SELECT "id"

7

 

FROM TABLE(CAST(

8

 

GET_ALL_CHILDREN({родительская_вершина},

9

 

'TABLE')

10

 

AS "nodes_collection")))

 

 

 

Если же предположить, что функции GET_ALL_CHILDREN у нас нет, решение можно построить следующим образом.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 482/545

Пример 46: формирование и анализ иерархических структур

В MySQL мы берём запрос, вокруг которого построена функция в решении{476} задачи 7.1.1.a{475}, и используем его напрямую как источник списка идентификаторов дочерних страниц.

MySQL Решение 7.1.1.b

1SELECT `sp_id`,

2`sp_name`

3 FROM `site_pages`

4WHERE `sp_id` = {родительская_вершина}

5OR FIND_IN_SET

6(`sp_id`,

7(SELECT GROUP_CONCAT(`children_ids`)

8

 

FROM

(SELECT

`sp_id`,

9

 

 

@parent_values :=

10

 

 

(

 

11

 

 

SELECT GROUP_CONCAT(`sp_id` SEPARATOR ',')

12

 

 

FROM

`site_pages`

13

 

 

WHERE

FIND_IN_SET(`sp_parent`, @parent_values) > 0

14

 

 

) AS `children_ids`

15

 

 

FROM

`site_pages`

16

 

 

JOIN

(SELECT @parent_values := {родительская_вершина})

17

 

 

 

AS `initialisation`

18

 

 

WHERE

`sp_id` IN (@parent_values)

 

 

 

 

 

19) AS `prepared_data`)

20)

ВMS SQL Server мы берём рекурсивные общие табличные выражения, вокруг которых построены функции в решении{476} задачи 7.1.1.a{475}, и, добавив в выборку имя страницы (поле sp_name), используем полученный результат как источ-

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

Обратите внимание на тот факт, что MS SQL Server допускает создание рекурсивных общих табличных выражений без явного указания списка колонок, в то время как в Oracle этот список обязателен.

MS SQL Решение 7.1.1.b

1WITH [tree]

2AS

3(

4SELECT [sp_id],

5[sp_parent],

6

 

 

[sp_name]

7

 

FROM

[site_pages]

8

 

WHERE

[sp_id] = {родительская_вершина}

9UNION ALL

10SELECT [inner].[sp_id],

11[inner].[sp_parent],

12

 

 

[inner].[sp_name]

13

 

FROM

[site_pages] AS [inner]

14JOIN [tree]

15ON [inner].[sp_parent] = [tree].[sp_id]

16)

17SELECT [sp_id],

18[sp_name]

19FROM [tree]

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 483/545

Пример 46: формирование и анализ иерархических структур

Oracle Решение 7.1.1.b

1WITH "tree" ("sp_id", "sp_parent", "sp_name")

2AS

3(

4SELECT "sp_id",

5"sp_parent",

6"sp_name"

7

 

FROM

"site_pages"

8

 

WHERE

"sp_id" = {родительская_вершина}

 

 

 

 

9UNION ALL

10SELECT "inner"."sp_id",

11"inner"."sp_parent",

12"inner"."sp_name"

13

 

FROM "site_pages" "inner"

14JOIN "tree"

15ON "inner"."sp_parent" = "tree"."sp_id"

16)

17SELECT "sp_id",

18"sp_name"

19FROM "tree"

Если же отойти от традиции, в рамках которой мы рассматриваем во всех трёх СУБД максимально похоже решения, то в Oracle данную задачу можно решить с помощью конструкции CONNECT BY.

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

Oracle Решение 7.1.1.b (альтернативный вариант)

1SELECT "sp_id",

2"sp_parent",

3"sp_name",

4LEVEL

5 FROM "site_pages"

6START WITH "sp_id" = {родительская_вершина}

7CONNECT BY PRIOR "sp_id" = "sp_parent";

Для страницы с идентификатором 2, этот запрос вернёт следующие данные.

sp_id

sp_parent

sp_name

LEVEL

2

1

Читателям

1

5

2

Новости

2

6

2

Статистика

2

12

6

Текущая

3

13

6

Архивная

3

14

6

Неофициальная

3

Но и это ещё не всё: функция SYS_CONNECT_BY_PATH позволяет для каждой вершины формировать полный путь, связывающий её с родительской (для которой строится список дочерних элементов).

Oracle Решение 7.1.1.b (альтернативный вариант)

1SELECT LPAD(' ', 2 * LEVEL, ' ') || "sp_name" "debug",

2"sp_id",

3"sp_parent",

4"sp_name",

5SYS_CONNECT_BY_PATH("sp_name", '/') "path_with_names",

6

 

SYS_CONNECT_BY_PATH("sp_id", ',') "path_with_ids"

7

 

FROM "site_pages"

8START WITH "sp_id" = {родительская_вершина}

9CONNECT BY PRIOR "sp_id" = "sp_parent"

10ORDER SIBLINGS BY "sp_name"

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 484/545

Пример 46: формирование и анализ иерархических структур

Для страницы с идентификатором 2, этот запрос вернёт следующие данные.

debug

sp_id

sp_par-

sp_name

path_with_names

path_with_ids

 

 

ent

 

 

 

Читателям

2

1

Читателям

/Читателям

,2

Новости

5

2

Новости

/Читателям/Новости

,2,5

Стати-

6

2

Статистика

/Читателям/Статистика

,2,6

стика

 

 

 

 

 

Архивная

13

6

Архивная

/Читателям/Статистика/Ар-

,2,6,13

 

 

 

 

хивная

 

Неофи-

14

6

Неофици-

/Читателям/Статистика/Не-

,2,6,14

циальная

 

 

альная

официальная

 

Текущая

12

6

Текущая

/Читателям/Статистика/Теку-

,2,6,12

 

 

 

 

щая

 

На этом решение данной задачи завершено.

Решение 7.1.1.c{475}.

В MySQL нет рекурсивных запросов, нет возможности вернуть из функции таблицу, нет общих табличных выражений — остаётся использовать алгоритм с циклом, в котором на каждом шаге мы поднимаемся на один уровень иерархии вверх, пока не достигнем корневой вершины (ссылка на родителя равна NULL).

Здесь мы последовательно подменяем (строки 12-15) значение идентификатора текущего узла и накапливаем (строки 16-19) все полученные значения в строковой переменной, которая и является результатом работы функции.

Обратите внимание, что MySQL допускает указание RETURN прямо в объявлении обработчика ситуации «запрос вернул пустой результат» (строка 7), и таким образом нет необходимости явно делать RETURN далее в коде функции.

MySQL

Решение 7.1.1.c (код функции)

1DELIMITER $$

2CREATE FUNCTION GET_PATH_TO_ROOT(start_node INT) RETURNS TEXT

3NOT DETERMINISTIC

4BEGIN

5DECLARE path_to_root TEXT;

6DECLARE current_node INT;

7DECLARE EXIT HANDLER FOR NOT FOUND RETURN path_to_root;

8

9SET current_node = start_node;

10SET path_to_root = start_node;

11LOOP

12SELECT `sp_parent`

13

 

INTO

current_node

14

 

FROM

`site_pages`

15

 

WHERE

`sp_id` = current_node;

16IF (current_node IS NOT NULL)

17THEN

18SET path_to_root = CONCAT(path_to_root, ',', current_node);

19END IF;

20END LOOP;

21END$$

22DELIMITER ;

Использовать полученную функцию можно так.

MySQL Решение 7.1.1.c (пример использования функции)

1 SELECT GET_PATH_TO_ROOT(14)

На этом решение для MySQL завершено.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 485/545

Пример 46: формирование и анализ иерархических структур

Переходим к MS SQL Server. Поскольку в данной СУБД есть возможность возвратить из функции результат в виде таблицы, мы реализуем оба варианта поведения — и возврат таблицы, и возврат строки.

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

Встроках 19-28 мы проверяем необходимость вернуть результат в виде набора идентификаторов, разделённых запятыми и, если такая необходимость есть, собираем все данные из результирующей таблицы в строку (строки 21-24 кода), очищаем результирующую таблицу (строка 25 кода) и помещаем в неё полученную строку (строки 26-27 кода).

MS SQL

Решение 7.1.1.c (код функции)

1CREATE FUNCTION GET_PATH_TO_ROOT(@current_node INT, @mode VARCHAR(50))

2RETURNS @path TABLE

3(

4id VARCHAR(max)

5)

6AS

7BEGIN

8DECLARE @all_as_string VARCHAR(max) = '';

9WHILE (@current_node IS NOT NULL)

10BEGIN

11INSERT INTO @path

12SELECT CAST(@current_node AS VARCHAR);

13

 

 

 

14

 

SET @current_node = (SELECT

[sp_parent]

15

 

FROM

[site_pages]

16

 

WHERE

[sp_id] = @current_node);

17

 

END;

 

18

 

 

 

 

 

 

 

19IF (@mode = 'STRING')

20BEGIN

21SET @all_as_string = (SELECT STUFF((SELECT ',' + CAST([id] AS VARCHAR)

22

 

FROM

@path

23

 

FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'),

24

 

1, 1, ''));

25DELETE FROM @path;

26INSERT INTO @path

27SELECT @all_as_string;

28END;

29

30RETURN

31END;

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

MS SQL Решение 7.1.1.c (пример использования функции)

1SELECT * FROM GET_PATH_TO_ROOT(14, 'TABLE');

2SELECT * FROM GET_PATH_TO_ROOT(14, 'STRING');

Поскольку MS SQL Server поддерживает рекурсивные общие табличные выражения, эту задачу можно решить также с их помощью. Для краткости мы не будем создавать отдельную функцию, но приведём запрос, который даже сам по себе возвращает именно такой результат, какой требуется по условию задачи.

JOIN в строке 11 как раз и обеспечивает необходимое нам рекурсивное по-

ведение.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 486/545

Пример 46: формирование и анализ иерархических структур

MS SQL Решение 7.1.1.c (альтернативный вариант)

1WITH [path_to_root] AS

2(

3SELECT [sp_id],

4[sp_parent]

5

 

FROM

[site_pages]

6

 

WHERE

[sp_id] = {исходная_вершина}

7UNION ALL

8SELECT [inner].[sp_id],

9[inner].[sp_parent]

10

FROM [site_pages] AS [inner]

11JOIN [path_to_root] ON [path_to_root].[sp_parent] = [inner].[sp_id]

12)

13SELECT [sp_id] FROM [path_to_root]

На этом решение для MS SQL Server завершено.

Переходим к Oracle и реализуем решение по аналогии с MS SQL Server.

Oracle

Решение 7.1.1.c (код функции)

1CREATE TYPE "ptr_tree_node" AS OBJECT("id" VARCHAR(32767));

2/

3

4CREATE TYPE "ptr_nodes_collection" AS TABLE OF "ptr_tree_node";

5/

6

 

 

7

 

CREATE OR REPLACE FUNCTION GET_PATH_TO_ROOT(start_id NUMBER,

8

 

function_mode VARCHAR)

 

 

 

9RETURN "ptr_nodes_collection"

10AS

11result_collection "ptr_nodes_collection" := "ptr_nodes_collection"();

12all_as_string VARCHAR(32767);

13temp_int_value NUMBER(10);

14BEGIN

15temp_int_value := start_id;

16

17WHILE (temp_int_value IS NOT NULL)

18LOOP

19IF (function_mode = 'TABLE')

20THEN

21result_collection.extend;

22result_collection(result_collection.last) :=

23

 

"ptr_tree_node"(TO_CHAR(temp_int_value));

24ELSE

25all_as_string := all_as_string || ',' || temp_int_value;

26END IF;

27SELECT "sp_parent" INTO temp_int_value

28FROM "site_pages"

29WHERE "sp_id" = temp_int_value;

30END LOOP;

31

32 all_as_string := SUBSTR(all_as_string, 2); 33

34IF (function_mode != 'TABLE')

35THEN

36SELECT "ptr_tree_node"(TO_CHAR(all_as_string))

37BULK COLLECT INTO result_collection

38FROM DUAL;

39END IF;

40

41RETURN result_collection;

42END;

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 487/545

Пример 46: формирование и анализ иерархических структур

Поскольку в Oracle нельзя присваивать новое значение входному параметру функции, мы используем временную переменную (строки 13 и 15) для хранения значений идентификаторов вершин и использования в цикле.

Вотличие от MS SQL Server, где внутри функции у нас есть полноценная таблица для хранения данных, в Oracle мы используем коллекцию, потому для упрощения кода мы сразу в теле цикла проверяем, придётся ли нам возвратить колонку идентификаторов (тогда мы добавляем их в коллекцию) или строку с их перечислением (тогда мы накапливаем их в строковой переменной).

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

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

Oracle Решение 7.1.1.c (пример использования функции)

1SELECT *

2FROM TABLE(CAST(GET_PATH_TO_ROOT(14, 'TABLE') AS "ptr_nodes_collection"));

3

4SELECT *

5FROM TABLE(CAST(GET_PATH_TO_ROOT(14, 'STRING') AS "ptr_nodes_collection"));

Поскольку Oracle (как и MS SQL Server) поддерживает рекурсивные общие табличные выражения, эту задачу можно решить также с их помощью. Для краткости мы не будем создавать отдельную функцию, но приведём запрос, который даже сам по себе возвращает именно такой результат, какой требуется по условию задачи.

Oracle Решение 7.1.1.c (альтернативный вариант)

1WITH "path_to_root" ("sp_id", "sp_parent") AS

2(

3SELECT "sp_id",

4"sp_parent"

5

 

FROM

"site_pages"

6

 

WHERE

"sp_id" = {исходная_вершина}

7UNION ALL

8SELECT "inner"."sp_id",

9"inner"."sp_parent"

10FROM "site_pages" "inner"

11JOIN "path_to_root" ON "path_to_root"."sp_parent" = "inner"."sp_id"

12)

13SELECT "sp_id" FROM "path_to_root"

Как и в решении задачи 7.1.1.b, мы рассмотрим ещё один вариант, доступный только в Oracle. На основе выражения CONNECT BY и функции SYS_CONNECT_BY_PATH очень легко получается решение с представлением результата в виде строки идентификаторов.

Oracle Решение 7.1.1.c (альтернативный вариант)

1 SELECT SUBSTR(SYS_CONNECT_BY_PATH("sp_id", ','), 2) "path_with_ids"

2 FROM "site_pages"

3WHERE "sp_id" = {исходная_вершина}

4START WITH "sp_id" = (SELECT "sp_id"

5

 

FROM

"site_pages"

6

 

WHERE

"sp_parent" IS NULL)

7CONNECT BY PRIOR "sp_id" = "sp_parent"

8ORDER SIBLINGS BY "sp_name"

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 488/545

Пример 46: формирование и анализ иерархических структур

Единственная особенность заключается в последовательности размещения идентификаторов: во всех ранее рассмотренных вариантах корневая вершина находилась справа (например, для вершины 14 последовательность была 14,6,2,1), а здесь корневая вершина будет находиться слева (т.е. получится 1,2,6,14).

На этом решение данной задачи завершено.

Задание 7.1.1.TSK.A: создать функцию, возвращающую список идентификаторов всех дочерних вершин заданной вершины (например, идентификаторов всех подстраниц страницы «Читателям») на глубину, не более заданной.

Задание 7.1.1.TSK.B: написать запрос для показа всего поддерева заданной вершины дерева, включая саму родительскую вершину (например, всех подстраниц страницы «Читателям», включая саму эту страницу), в котором с каждого уровня иерархии в выборку попадает не более одной вершины.

Задание 7.1.1.TSK.C: написать функцию, возвращающую список идентификаторов вершин на пути от корня дерева к заданной вершине (например, идентификаторов всех вершин на пути от страницы «Главная» к странице «Архивная»).

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 489/545