
Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle
.pdf
Пример 36: выборка и модификация данных с использованием хранимых функций
Решение 5.1.1 .с
1DROP FUNCTION IF EXISTS BOOKS DELTA;
2DELIMITER $$
3CREATE FUNCTION BOOKS DELTA() RETURNS INT
4BEGIN
5DECLARE old books count INT DEFAULT 0
6DECLARE new_books_count INT DEFAULT 0
7
8 SET old_books_count := (SELECT 'total' FROM 'books_statistics'); 9
10UPDATE 'books statistics'
11JOIN
12(SELECT IFNULL('total', 0 AS 'total',
13IFNULL('given', 0 AS 'given',
14IFNULL('total' - 'given', 0) AS 'rest'
15 |
FROM |
(SELECT (SELECT SUM('b quantity') |
|
|
16 |
|
FROM |
'books') |
AS 'total', |
17 |
|
(SELECT COUNT('sb book') |
|
|
18 |
|
FROM |
'subscriptions' |
|
19 |
|
WHERE |
'sb is active' = 'Y') AS 'given') |
20AS 'prepared data') AS 'src'
21SET 'books statistics' 'total' = 'src' 'total',
22'books statistics' 'given' = 'src' 'given',
23'books statistics' 'rest' = 'src' 'rest';
25SET new books count := (SELECT 'total' FROM 'books statistics');
26
27RETURN new books count - old books count ;
28END;
29$$
30DELIMITER ;
Решение для MySQL готово, а т.к. решения для MS SQL Server не существует, сразу переходим к Oracle, где полностью воспроизведём логику решения для
MySQL.
Oracl |
і Решение 5.1.1.c (создание таблицы и инициализация данных) |
| |
||||
e |
||||||
|
|
|
|
|
||
1 |
-- Создание таблицы: |
|
|
|||
2 |
CREATE TABLE "books statistics" |
|
|
|||
3 |
( |
|
|
|
|
|
4 |
|
"total" NUMBER(10 , |
|
|
||
5 |
|
"given" NUMBER(10 , |
|
|
||
6 |
|
"rest" |
NUMBER(10 |
|
|
|
7 |
); |
|
|
|
|
|
8 |
|
|
|
|
|
|
9 |
-- Инициализация данных: |
|
|
|||
10 |
INSERT INTO "books statistics" |
|
|
|||
11 |
|
("total" |
|
|
||
12 |
|
"given" |
|
|
||
13 |
|
"rest" |
|
|
||
14 |
SELECT "total", |
|
|
|||
15 |
|
"given", |
|
|
||
16 |
|
("total" - "given") AS "rest" |
|
|||
17 |
FROM |
(SELECT SUM("b quantity" |
AS "total" |
|
||
18 |
|
FROM |
"books" |
|
|
|
19 |
JOIN (SELECT COUNT "sb book" |
AS "given" |
|
|||
20 |
|
FROM |
"subscriptions" |
|
|
|
21 |
|
WHERE |
"sb is active" = |
'Y') |
|
|
22 |
ON 1 = 1; |
|
|
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 390/545

Пример 36: выборка и модификация данных с использованием хранимых функций
Oracl |
і |
Решение 5.1.1.c (код функции) |
I |
|
||
e |
|
|||||
|
|
|
|
|
|
|
1 |
CREATE OR REPLACE FUNCTION BOOKS DELTA RETURN NUMBER IS |
|||||
2 |
PRAGMA AUTONOMOUS TRANSACTION; |
|
||||
3 |
old books count NUMBER; |
|
|
|||
4 |
new books count NUMBER; |
|
|
|||
5 |
BEGIN |
|
|
|
|
|
6 |
SELECT "total" INTO old books count FROM "books statistics"; |
|||||
7 |
COMMIT; |
|
|
|
|
|
8 |
|
|
|
|
|
|
9 |
UPDATE "books statistics" |
|
|
|||
10 |
SET |
"total", "given", "rest" |
= |
|||
11 |
(SELECT "total", |
|
|
|
||
12 |
|
|
"given", |
|
|
|
13 |
|
|
"total" - "given" |
AS "rest" |
||
14 |
FROM |
|
(SELECT SUM "b quantity") AS "total" |
|||
15 |
|
|
FROM |
"books") |
|
|
16 |
JOIN (SELECT COUNT("sb book") AS "given" |
|||||
17 |
|
|
FROM |
"subscriptions" |
||
18 |
|
|
WHERE |
"sb is active" = 'Y') |
||
19 |
ON 1 = 1 ; |
|
|
|
||
20 |
COMMIT; |
|
|
|
|
|
21 |
|
|
|
|
|
|
22 |
SELECT "total" INTO new books count FROM "books statistics"; |
|||||
23 |
COMMIT; |
|
|
|
|
|
24 |
|
|
|
|
|
|
25 |
RETURN |
new books count - old books count ; |
||||
26 |
END; |
|
|
|
|
|
Поскольку у Oracle есть ряд ограничений на модификацию данных из кода хранимых функций, нам нужно реализовать две идеи:
•выполнять функцию в автономной транзакции (строка 2);
•подтверждать транзакцию в теле функции после выполнения каждого запроса (строки 7, 20, 23), т.к. в противном случае возникает ситуация взаимной блокировки между запросами на чтение и обновление данных).
Получить результат выполнения функции можно запросом.
Oracle Решение 5.1.1.c (запрос для получения результата работы функции)
1 SELECT BOOKS_DELTA FROM dual
На этом решение данной задачи завершено.
Задание 5.1.1.TSK.A: создать хранимую функцию, получающую на вход &идентификатор читателя и возвращающую список идентификаторов книг,
которые он уже прочитал и вернул в библиотеку.
& Задание 5.1.1.TSK.B: создать хранимую функцию, возвращающую список первого диапазона свободных значений автоинкрементируемых первичных ключей в указанной таблице (например, если в таблице есть первичные ключи
1,4, 8, то первый свободный диапазон — это значения 2 и 3).
& Задание 5.1.1.TSK.C: дополнить решение{355} задачи 5.1.1. b{352} для Oracle двумя вариантами реализации хранимой функции, в которых:
•функция возвращает таблицу из одного поля, в котором хранится весь список значений свободных ключей;
•функция возвращает строку, в которой через запятую перечислены все значения свободных ключей.
Задание 5.1.1.TSK.D: создать хранимую функцию, актуализирующую данные в таблице subscriptions_ready (см. задачу 3.1.2. b{215}) и возвращающую число, показывающее изменение количества выдач книг.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 391/545

Пример 37: контроль операций с данными с использованием хранимых функций
5.1.2.Пример 37: контроль операций с данными с использованием хранимых функций
ОЗадача 5.1.2.a{370}: создать хранимую функцию, автоматизирующую проверку условий задачи 4.2.1.a{315}, т.е. возвращающую значение 1 (все условия
выполнены) или -1, -2, -3 (если хотя бы одно условие нарушено, модуль числа соответствует номеру условия) в зависимости от того, выполняются ли следующие условия:
•дата выдачи книги не может находиться в будущем;
•дата возврата книги не может находиться в прошлом (только в случае вставки данных);
•дата возврата книги не может быть меньше даты выдачи книги.
ОЗадача 5.1.2.b{373}: создать хранимую функцию, автоматизирующую проверку условий задачи 4.2.2.a{338}, т.е. возвращающую 1, если имя читателя
содержит хотя бы два слова и одну точку, и 0, если это условие нарушено.
Ожидаемый результат 5.1.2.a.
Функция возвращает 1, если все условия задачи выполнены, и 0, если хотя бы одно условие нарушено.
Ожидаемый результат 5.1.2.b.
Функция возвращает 1, если условие задачи выполнено, и 0, если оно нару-
шено.
Решение 5.1.2.a{370}.
Во всех трёх СУБД логика решения данной задачи будет одинакова: мы передадим в функцию три параметра (дату выдачи книги, дату возврата книги, признак обновления данных), проверим в теле функции выполнение условий и вернём соответствующее число.
MySQL I |
Решение 5.1.2.a (код функции) |
| |
1DELIMITER $$
2CREATE FUNCTION CHECK SUBSCRIPTION DATES sb start DATE,
3 |
sb |
finish |
DATE, |
4 |
is |
insert |
INT) |
5RETURNS INT
6DETERMINISTIC
7BEGIN
8DECLARE result INT DEFAULT 1;
10 -- Блокировка выдач книг с датой выдачи в будущем
11IF sb start > CURDATE())
12THEN
13SET result = 1;
14END IF;
15 |
|
|
|
16 |
-- |
Блокировка выдач книг с датой возврата в прошлом. |
|
17 |
IF |
( sb finish < |
AND is insert = 1 ) |
18THEN
19SET result = 2 ;
20END IF;
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 392/545



Пример 37: контроль операций с данными с использованием хранимых функций
'ЬАЙ'
Решение 5.1.2.b{370}.
По сравнению с предыдущей задачей здесь всё будет ещё проще: нужно просто «обернуть» в функцию две проверки, на основе результата которых возвратить 1 или 0.
Только в решении для MS SQL Server будет одна необычная деталь: мы вынуждены использовать промежуточную переменную и возвращать её значение в самом конце тела функции, т.к. данная СУБД требует, чтобы последним выражением внутри хранимой функции был оператор RETURN.
MySQL |
Решение 5.1.2.b (код функции) [ |
|
|
1 |
DROP ... FUNCTION. IF |
EXISTS CHECK_SUBSCRIBER_NAME; |
|
2 |
DELIMITER $$ |
|
|
3 |
CREATE FUNCTION CHECK_SUBSCRIBER_NAME |
subscriber_name VARCHAR(150 ) |
4RETURNS
5INT DETERMINISTIC
6BEGIN
7IF ((CAST subscriber_name AS CHAR CHARACTER SET cp1251 REGEXP
8CAST('Л[a-zA-Za-яА-ЯёЁХ'-]+([лa-zA-Zа-яА-ЯёЁ\'-]+[a-zA-Za-HA-
9ЯёЁ\'.-]+){1,}$' AS CHAR CHARACTER SET cp1251)) = 0)
10 |
OR (LOCATE('.', |
subscriber_name) = 0) |
11THEN
12RETURN 0; ELSE
13RETURN 1; END IF;
14END; $$ DELIMITER ;
16MySQL Решение 5.1.2.b (код для проверки работы функции)
17 |
1 |
SELECT CHECK_SUBSCRIBER_NAME('Иванов'); |
|
2 |
SELECTCHECK_SUBSCRIBER_NAME('Иванов И' ); |
3 |
SELECT |
CHECK SUBSCRIBER NAME('Иванов И.'); |
MS SQL Решение 5.1.2.b (код функции)
1CREATE FUNCTION CHECK SUBSCRIBER NAME @subscriber name NVARCHAR 150))
2RETURNS INT
3WITH SCHEMABINDING
4AS
5BEGIN
6DECLARE @result INT = -1;
7
8IF ((CHARINDEX(' ', LTRIM(RTRIM @subscriber name )) = 0) OR
9(CHARINDEX('.', @subscriber name = 0 )
10BEGIN
11SET @result = 0;
12END
13ELSE
14BEGIN
15SET @result = 1;
16END;
17
18RETURN @result
19END;
20GO
MS SQL |
Решение 5.1.2.b (код для проверки работы функции) |
1SELECT dbo.CHECK_SUBSCRIBER_NAME('Иванов');
2SELECT dbo.CHECK_SUBSCRIBER_NAME('Иванов И' );
3SELECT dbo.CHECK SUBSCRIBER NAME('Иванов И.' );
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 395/545

Пример 37: контроль операций с данными с использованием хранимых функций |
|||||
Oracl |
і |
Решение 5.1.2.b (код функции) |
| |
|
|
e |
|
|
|||
|
|
|
|
|
|
1 |
CREATE OR REPLACE |
|
|
|
|
2 |
FUNCTION CHECK SUBSCRIBER NAME (subscriber name NVARCHAR2) |
||||
3 |
RETURN NUMBER DETERMINISTIC IS |
|
|
||
4 |
BEGIN |
|
|
|
|
5 |
IF ((NOT REGEXP LIKE subscriber name, 'Л[a-zA-Zа-яA-ЯёЁ''-]+([Лa-zA-Zа-яA- |
||||
6 |
ЯёЁ' '-^[a-zA-Za-яА-ЯёЁ' ' .-]+){1,}$')) |
|
|||
7 |
|
OR (INSTRC subscriber name |
'.', 1, 1 |
= 0)) |
|
8 |
|
THEN |
|
|
|
9 |
|
RETURN 0; |
|
|
|
10 |
|
ELSE |
|
|
|
11 |
|
RETURN 1; |
|
|
|
12 |
|
END IF; |
|
|
|
13 |
END; |
|
|
|
|
Oracle |
Решение 5.1.2.b (код для |
|
|
|
|
1 |
SELECT CHECK_SUBSCRIBER_NAME(N'Иванов') FROM dual; |
||||
2 |
SELECT CHECK_SUBSCRIBER_NAME(N'Иванов И') FROM dual; |
||||
3 |
SELECT CHECK SUBSCRIBER NAME(N'Иванов И.') FROM dual; |
||||
|
На этом решение данной задачи завершено. |
|
Задание 5.1.2.TSK.A: переписать решения*315*, *338} задач 4.2.1.a*315} и 4.2.2. a*338} с использованием хранимых функций, созданных в решениях*37^ *373} задач 5.1.2.a*370} и 5.1.2.b*370} соответственно.
Задание 5.1.2.TSK.B: создать хранимую функцию, автоматизирующую &проверку условий задачи 4.2.1.b*315}, т.е. возвращающую 1, если у читателя на
руках сейчас менее десяти книг, и 0 в противном случае.
& Задание 5.1.2.TSK.C: создать хранимую функцию, автоматизирующую проверку условий задачи 4.2.2.b*338}, т.е. возвращающую 1, если книга издана менее ста лет назад, и 0 в противном случае.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 396/545

Пример 38: выполнение динамических запросов с помощью хранимых процедур
5.2. Использование хранимых процедур
5.2.1.Пример 38: выполнение динамических запросов с помощью хранимых процедур
ОЗадача 5.2.1.a{375}: создать хранимую процедуру, устраняющую промежутки в последовательности значений первичного ключа для заданной таблицы
(например, если значения первичного ключа были равны 4, 7, 9, то после выполнения хранимой процедуры они станут равны 1,2, 3).
□ Задача 5.2.1.b{382}: создать хранимую процедуру, формирующую список представлений, триггеров и внешних ключей для указанной таблицы.
Ожидаемый результат 5.2.1.a.
После выполнения хранимой процедуры, в которую первыми двумя параметрами передано имя обрабатываемой таблицы и её первичного ключа, значения первичного ключа в таблице принимают вид 1, 2, 3, ... (т.е. начинаются с 1 и идут без пропусков), а сама хранимая процедура возвращает информацию о том, сколько значений первичного ключа было изменено.
Ожидаемый результат 5.2.1.b.
После выполнения хранимой процедуры, в которую первым параметром передано имя обрабатываемой таблицы, формируется и возвращается результирующая таблица вида:
object_type |
object_name |
|
foreign_key |
FK_1 |
|
foreign key |
FK 2 |
|
trigger |
TRG_1 |
|
trigger |
TRG 2 |
|
view |
VIEW 1 |
|
view |
VIEW_2 |
|
|
'Vf Решение 5.2.1 .a{375}. |
Т радиционно начнём решение задачи с MySQL. В отличие от хранимых функций в хранимые процедуры данной СУБД позволяют формировать и выполнять динамические SQL-запросы.
Прежде, чем начать рассмотрение кода хранимой процедуры, сделаем два важных замечания:
•выполнять динамические запросы и помещать результаты их работы в переменные можно только с использованием т.н. «сессионных переменных20» (имена которых начинаются со знака @);
•имена переменных, в которые помещается результат выполнения запроса, не должны совпадать с именами параметров хранимой процедуры (и, в некоторых случаях, с именами полей, возвращаемых запросом21).
20http://stackoverflow.com/questions/1009954/mysql-variable-vs-variable-whats-the-difference
21http://dba.stackexchange.com/questions/112285/select-into-variable-results-in-null-or-idk
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 397/545


Пример 38: выполнение динамических запросов с помощью хранимых процедур
DELIMITER ;
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016-2018 Стр: 399/545