Пример 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