Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle
.pdfПример 45: управление транзакциями в триггерах, хранимых функциях и процедурах
Решение для Oracle выглядит следующим образом. Да, именно так и выглядит, т.к. в Oracle нет такого явления, как автоподтверждение транзакций — этот эффект может быть реализован некоторыми средствами работы с СУБД, но сама СУБД всегда ждёт явного COMMITT или ROLLBACK.
Oracle |
Решение 6.2.3.b (код функции) |
1CREATE FUNCTION NO AUTOCOMMITT
2RETURN INT
3DETERMINISTIC
4IS
5BEGIN
6DBMS OUTPUT.PUT LINE('Have a nice day :)');
7RETURN 1
8END;
Проверить работоспособность и корректность представленного решения можно выполнением следующего кода.
Oracle Решение 6.2.3.Ь (код для проверки работоспособности решения)
1 SET SERVEROUTPUT ON;
2 SELECT NO AUTOCOMMITT FROM DUAL;
На этом решение данной задачи завершено.
ЧРешение 6.2.3.C 465.
Идея решения данной задачи состоит в том, чтобы использовать такой уровень изолированности транзакций, который меньше всего подвержен влиянию со стороны блокировок, порождённых другими транзакциями.
В MySQL таким уровнем является READ UNCOMMITTED, в MS SQL Server —
тоже READ UNCOMMITTED или SNAPSHOT (но SNAPSHOT может приводить к допол-
нительным расходам ресурсов), в Oracle чтение данных всегда происходит в независимом режиме, потому в этой СУБД можно использовать READ COMMITTED (тем более, что READ UNCOMMITTED в Oracle нет).
Решение для MySQL выглядит следующим образом.
MySQL і |
Решение 6.2.3.C (код процедуры) |
[ |
1DELIMITER $$................. ........................
2CREATE PROCEDURE COUNT_ROWS(IN table_name VARCHAR 150),
3 |
OUT rows_in_table INT) |
4 |
BEGIN |
5 |
SET SESSION TRANSACTION |
6 |
ISOLATION LEVEL READ UNCOMMITTED; |
7 |
|
8 |
SET @count_query = |
9 |
CONCAT('SELECT COUNT(1) INTO @rows_found |
10 |
FROM ' , table_name); |
11 |
|
12PREPARE count_stmt FROM @count_query
13EXECUTE count_stmt;
14DEALLOCATE PREPARE count_stmt
15
16SET rows_in_table := @rows_found
17END;
18$$
19DELIMITER ;
Проверить работоспособность и корректность представленного решения можно выполнением следующего кода.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 500/545
Пример 45: управление транзакциями в триггерах, хранимых функциях и процедурах
Задание 6.2.3.TSK.A: создать на таблице subscriptions триггер, определяющий уровень изолированности транзакции, в котором сейчас проходит операция обновления, и отменяющий операцию, если уровень изолированности транзакции отличен от REPEATABLE READ.
Задание 6.2.3.TSK.B: создать хранимую функцию, порождающую исключительную ситуацию в случае, если выполняются оба условия:
•режим автоподтверждения транзакций выключен;
•функция запущена из вложенной транзакции.
Подсказка: эта задача имеет решение только для MS SQL Server.
Задание 6.2.3.TSK.C: создать хранимую процедуру, выполняющую подсчёт количества записей в указанной таблице таким образом, чтобы она возвращала максимально корректные данные, даже если для достижения этого результата придётся пожертвовать производительностью.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 502/545
Пример 46: формирование и анализ иерархических структур
Рисунок 7.b — Визуальное представление карты сайта
Теперь, когда все данные подготовлены, мы можем переходить к задачам.
Задача 7.1.1.a{476}: создать функцию, возвращающую список идентификаторов всех дочерних вершин заданной вершины (например, идентификаторов всех подстраниц страницы «Читателям»).
Задача 7.1.1.b{482}: написать запрос для показа всего поддерева заданной вершины дерева, включая саму родительскую вершину (например, всех подстраниц страницы «Читателям», включая саму эту страницу).
Задача 7.1.1.c{485}: написать функцию, возвращающую список идентификаторов вершин на пути от заданной вершины к корню дерева (например, идентификаторов всех вершин на пути от страницы «Архивная» к странице
«Главная»).
Ожидаемый результат 7.1.1 .a.
Для вершины с идентификатором 2 (страница «Читателям») функция должна возвратить следующие данные: shildren_of_2
5,6,12,13,14
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 504/545
Пример 46: формирование и анализ иерархических структур
Ожидаемый результат 7.1.1.b.
Для вершины с идентификатором 2 (страница «Читателям») запрос должен возвратить следующие данные:
sp_id |
sp_name |
2 |
Читателям |
5 |
Новости |
6 |
Статистика |
12 |
Текущая |
13 |
Архивная |
14 |
Неофициальная |
Ожидаемый результат 7.1.1.С.
Для вершины с идентификатором 13 (страница «Архивная») запрос должен возвратить следующие данные: path
13
6 __
2 __
1
Также допускается вариант:
path
13,6,2,1
Решение 7.1.1.a{475}.
Решение данной задачи для MS SQL Server и Oracle можно очень легко построить на основе рекурсивных общих табличных выражений. В MySQL же общие табличные выражения не поддерживаются, равно как нет и иной возможности сделать «рекурсивный JOIN», потому для этой СУБД решение будет достаточно не-
тривиальным.
Сначала приведём готовый код функции и пример её использования.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 505/545
Пример 46: формирование и анализ иерархических структур
MySQL |
Решение 7.1.1.a (код функции) |
1DELIMITER $$
2CREATE FUNCTION GET_ALL_CHILDREN start_node INT)
3RETURNS TEXT
4BEGIN
5DECLARE result TEXT;
6SELECT GROUP_CONCAT('children_ids' SEPARATOR ',') INTO result
7 |
FROM |
( |
|
|
8 |
|
SELECT 'sp_id', @parent_values := |
||
9 |
|
|
( |
|
10 |
|
|
SELECT GROUP_CONCAT('sp_id' SEPARATOR ',') |
|
11 |
|
|
FROM |
'site_pages' |
12 |
|
|
WHERE FIND_IN_SET('sp_parent', |
|
13 |
|
|
|
@parent_values) > 0 |
14 |
|
|
) AS 'children_ids' |
|
15 |
|
FROM |
'site_pages' |
|
16 |
|
JOIN |
(SELECT @parent_values := start_nodel |
|
17 |
|
|
|
AS 'initialisation' |
18 |
|
WHERE |
'sp_id' IN |
@parent_values |
19) AS 'data';
20RETURN result 1
21END$$
22DELIMITER ;
Проверить работоспособность и корректность представленного решения можно выполнением следующего кода.
MySQL і Решение 7.1.1.a (пример использования функции) і
1-- Проверка работоспособности функции:
2SELECT GET_ALL_CHILDREN'2) AS 'shildren_of_2';
4-- Использование функции:
5SELECT 'sp_id', 'sp_name', GET_ALL_CHILDREN('sp_id') AS 'children'
6FROM 'site pages';
Второй запрос возвратит следующие данные (список всех страниц сайта библиотеки с указанием идентификаторов всех их подстраниц).
sp_id |
sp_name |
children |
1 |
Главная |
2,3,4,10,5,6,7,8,9,11,12,13,14 |
2 |
Читателям |
5,6,12,13,14 |
3 |
Спонсорам |
7,8,11 |
4 |
Рекламодателям |
9 |
5 |
Новости |
NULL |
6 |
Статистика |
12,13,14 |
7 |
Предложения |
NULL |
8 |
Истории успеха |
NULL |
9 |
Акции |
NULL |
10 |
Контакты |
NULL |
11 |
Документы |
NULL |
12 |
Текущая |
NULL |
13 |
Архивная |
NULL |
14 |
Неофициальная |
NULL |
Теперь рассмотрим, как работает это решение.
Очевидно, главной частью представленной функции является запрос в строках 6-19. Перепишем его без функции.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 506/545
Пример 46: формирование и анализ иерархических структур
|
|
Решение 7.1.1.a |
:, |
основана |
|
1 |
|
|
на |
|
|
SELECT GROUP CONCAT( 'children ids' SEPARATOR ',') AS 'children ids' |
|||||
2 |
FROM |
( |
|
|
|
3 |
|
SELECT 'sp_id', @parent_values := |
|||
4 |
|
|
( |
|
|
5 |
|
|
|
SELECT GROUP CONCAT('sp id' SEPARATOR ',') |
|
6 |
|
|
|
FROM |
'site_pages' |
7 |
|
|
|
WHERE FIND_IN_SET('sp_parent', |
|
8 |
|
|
|
|
@parent values > 0 |
9 |
|
|
) AS 'children ids' |
||
10 |
|
FROM |
'site_pages' |
||
11 |
|
JOIN |
(SELECT @parent values := {родительская вершина}) |
||
12 |
|
|
|
|
AS 'initialisation' |
13 |
|
WHERE |
'sp id' IN |
@parent values) |
14) AS 'prepared data'
Втаком виде этот запрос вернёт данные, представленные в ожидаемом результате задачи (если значение {родительская_вершина} равно 2).
Рассмотрим решение по частям.
1)Код в строках 11-12 инициализирует значение переменной @parent_values идентификатором вершины, для которой строится список идентификаторов дочерних вершин. В дальнейшем здесь будет храниться список вершин, но в начале работы здесь помещается только одно значение.
2)Код в строках 5-8 формирует набор идентификаторов дочерних элементов вершин, идентификаторы которых перечислены в переменной @parent_values. Полученный результат используется как новое значение переменной @parent_values.
3)Условие в строке 13 ограничивает выборку только теми вершинами, дочерние элементы которых ищутся на текущем шаге.
4)Алгоритм завершает работу, когда значение переменной @parent_values становится равным NULL.
5)Благодаря GROUP_CONCAT в строке 1 весь результат работу представляется
в виде одного списка идентификаторов, в котором они перечислены через запятую. Такое представление позволяет применять функцию FIND_IN_SET
для дальнейшей работы с полученными результатами.
Если выполнить отдельно строки 3-13 данного запроса, то будет получен следующий результат (сам результат представлен на сером фоне, чтобы не путать его с пояснениями).
Шаг |
sp_id |
children_ids |
Новое значение @parent_values |
Начальное состояние, поиск детей вершины 2. |
|
||
1 |
2 |
5,6 |
5,6 |
Теперь надо найти детей вершин 5 и 6 (строка с вершиной 6 «схлопывается» из-за GROUP_CON- CAT, т.е. в такой выборке мы теряем все значения sp_id, кроме самого первого, но в @parent_values благодаря тому же GROUP_CONCAT попадают дети всех sp_id, даже тех, чьи
значения мы «потеряли»).
2 |
5 |
12,13,14 |
12,13,14 |
Теперь надо найти детей вершин 12, 13 и 14 (строки с вершинами 13 и 14 «схлопываются» из-за GROUP_CONCAT, т.е. в такой выборке мы теряем все значения sp_id, кроме самого первого, но в @parent_values благодаря тому же GROUP_CONCAT попадают дети всех sp_id, даже тех, чьи значения мы «потеряли»).
3 |
12 |
NULL |
NULL |
Теперь надо найти детей вершин... NULL, т.е. никаких: конец алгоритма.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 507/545
Пример 46: формирование и анализ иерархических структур
Переходим к MS SQL Server. Здесь решение будет совершенно иным, т.к., вопервых, данная СУБД не поддерживает часть синтаксиса, необходимого для эмуляции решения MySQL, а во-вторых, с использованием возможностей MS SQL Server эта задача решается проще (несмотря на то, что кода будет больше).
MS SQL |
Решение 7.1.1 |
1 CREATE.a FUNCTION GET ALL CHILDREN @parent INT, @mode VARCHAR 50))
2RETURNS @all children TABLE
3(
4id VARCHAR(max)
5)
6AS
7BEGIN
8 IF @mode = 'TABLE')
9BEGIN
10WITH [tree] ([sp_id], [sp_parent])
11AS
12(
13SELECT [sp id]
14 |
|
[sp_parent] |
15 |
FROM |
[site_pages] |
16 |
WHERE |
[sp id] = @parent |
17UNION ALL
18SELECT [inner] [sp id]
19 |
|
[inner] [sp_parent] |
20 |
FROM |
[site_pages] AS [inner] |
21 |
|
JOIN [tree] |
22 |
|
ON [inner] [sp_parent] = [tree] [sp_id] |
23)
24INSERT @all children
25SELECT CAST [sp id] AS VARCHAR)
26 FROM [tree]
27WHERE [sp id] != @parent
28END
29ELSE
30BEGIN
31WITH [tree] ([sp_id] [sp_parent])
32AS
33(
34SELECT [sp id],
35 |
|
[sp_parent] |
36 |
FROM |
[site_pages] |
37 |
WHERE |
[sp id] = 2 |
38UNION ALL
39SELECT [inner] [sp id],
40 |
|
[inner] [sp_parent] |
41 |
FROM |
[site_pages] AS [inner] |
42 |
|
JOIN [tree] |
43 |
|
ON [inner] [sp_parent] = [tree] [sp_id] |
44)
45INSERT @all children
46SELECT STUFF((SELECT ',' + CAST [sp id] AS VARCHAR)
47 |
FROM |
[tree] |
48 |
|
WHERE [sp id] != 2 |
49 |
FOR XML PATH(''), TYPE) value('.', 'nvarchar (max) '), |
|
50 |
1, 1, |
''); |
51END;
52RETURN
53END;
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 508/545
Пример 46: формирование и анализ иерархических структур
Проверить работоспособность и корректность представленного решения можно выполнением следующего кода. Первый запрос возвратит результат в том виде, в котором это требуется по условию задачи (список идентификаторов, разделённых запятыми), второй запрос возвратит таблицу из одной колонки, где каждый идентификатор будет расположен в отдельной строке.
MS SQL Решение 7.1.1.a (пример использования функции) |
|
|||
|
1 |
SELECT * FROM |
GET_ALL_CHILDREN 2 |
'STRING') |
2 |
SELECT * FROM GET ALL CHILDREN 2, |
'TABLE'); |
|
Итак, рассмотрим решение. Мы создали именно табличную функцию затем, чтобы иметь возможность возвращать данные не только в виде списка идентификаторов, перечисленных через запятую, но и в виде таблицы из одной колонки, строками которой являются идентификаторы.
Вслучае, когда нам всё же нужен список идентификаторов, перечисленных через запятую, мы по-прежнему возвращаем таблицу из одной колонки, но в ней будет ровно одна строка, содержащая весь наш список.
Воснове решения лежит т.н. рекурсивное общее табличное выражение41. Рассмотрим его отдельно.
MS SQL |
Решение 7.1.1 .a (рекурсивное общее табличное выражение) |
|
1 |
WITH [tree] ([sp_id], [sp_parent]) |
||
2 |
AS |
|
|
3 |
( |
|
|
4 |
SELECT [sp_id], |
||
5 |
|
[sp_parent] |
|
6 |
FROM |
[site_pages] |
|
|
WHERE |
[sp_id] = {родительская_вершина} |
|
8 |
UNION ALL |
|
|
9 |
SELECT [inner] [sp_id] |
||
10 |
|
[inner] [sp_parent] |
|
11 |
FROM |
[site_pages] AS [inner] |
|
12 |
|
JOIN |
[tree] |
13 |
|
ON |
[inner] [sp_parent] = [tree] [sp_id] |
14 |
) |
|
|
15 |
SELECT |
[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} для эмуляции функции
41 https://msdn.microsoft.com/en-us/library/ms175972%28v=sql.110%29.aspx
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 509/545