Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Увеличим на пять единиц количество экземпляров книги, которой сейчас в библиотеке зарегистрировано 10 экземпляров (такая книга у нас одна):
|
Oracle |
|
Решение 3.1.2.a (проверка реакции на изменение количества книги) |
||
|
1 |
|
UPDATE |
"books" |
|
|
2 |
|
SET |
"b_quantity" = "b_quantity" + 5 |
|
|
|
|
|
|
|
3WHERE "b_quantity" = 10;
4COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
48 |
5 |
43 |
Стало |
53 |
5 |
48 |
Удалим книгу, оба экземпляра которой сейчас находится на руках у читателей (книга с идентификатором 1).
Oracle |
Решение 3.1.2.a (проверка реакции на удаление книги) |
1DELETE FROM "books"
2WHERE "b_id" = 1;
3COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
53 |
5 |
48 |
Стало |
51 |
3 |
48 |
Отметим, что по выдаче с идентификатором 3 книга возвращена:
|
Oracle |
|
|
Решение 3.1.2.a (проверка реакции на возврат книги) |
|
|
1 |
|
UPDATE |
"subscriptions" |
|
|
2 |
|
SET |
"sb_is_active" = 'N' |
|
3WHERE "sb_id" = 3;
4COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
51 |
3 |
48 |
Стало |
51 |
2 |
49 |
Отменим эту операцию (снова отметим книгу как невозвращённую):
|
Oracle |
|
|
Решение 3.1.2.a (проверка реакции на отмену возврата книги) |
|
|
1 |
|
UPDATE |
"subscriptions" |
|
2 |
|
SET |
"sb_is_active" = 'Y' |
||
3WHERE "sb_id" = 3;
4COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
51 |
2 |
49 |
Стало |
51 |
3 |
48 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 230/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Добавим в базу данных информацию о том, что читатель с идентификатором 2 взял в библиотеке книги с идентификаторами 5 и 6:
Oracle |
Решение 3.1.2.a (проверка реакции на выдачу книг) |
1INSERT ALL
2INTO "subscriptions" ("sb_subscriber",
3 |
|
"sb_book", |
4 |
|
"sb_start", |
5 |
|
"sb_finish", |
6 |
|
"sb_is_active") |
7 |
|
VALUES (2, |
8 |
|
5, |
9 |
|
TO_DATE('2016-01-10', 'YYYY-MM-DD'), |
10 |
|
TO_DATE('2016-02-10', 'YYYY-MM-DD'), |
11 |
|
'Y') |
12 |
|
INTO "subscriptions" ("sb_subscriber", |
13 |
|
"sb_book", |
14 |
|
"sb_start", |
15 |
|
"sb_finish", |
16 |
|
"sb_is_active") |
17 |
|
VALUES (2, |
18 |
|
6, |
19 |
|
TO_DATE('2016-01-10', 'YYYY-MM-DD'), |
20 |
|
TO_DATE('2016-02-10', 'YYYY-MM-DD'), |
21 |
|
'Y') |
22SELECT 1 FROM "DUAL";
23COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
51 |
3 |
48 |
Стало |
51 |
5 |
46 |
Удалим информацию о выдаче с идентификатором 42 (книга по этой выдаче уже возвращена):
Oracle |
Решение 3.1.2.a (проверка реакции на удаление выдачи с возвращённой книгой) |
1DELETE FROM "subscriptions"
2WHERE "sb_id" = 42;
3COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
51 |
5 |
46 |
Стало |
51 |
5 |
46 |
Удалим информацию о выдаче с идентификатором 62 (книга по этой выдаче ещё не возвращена):
Oracle |
Решение 3.1.2.a (проверка реакции на удаление выдачи с не возвращённой книгой) |
1DELETE FROM "subscriptions"
2WHERE "sb_id" = 62;
3COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
51 |
5 |
46 |
Стало |
51 |
4 |
47 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 231/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Наконец, удалим все книги (что также приведёт к каскадному удалению всех выдач):
Oracle |
Решение 3.1.2.a (проверка реакции на удаление всех книг) |
1DELETE FROM "books";
2COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
51 |
4 |
47 |
Стало |
0 |
0 |
0 |
Итак, все операции модификации данных в таблицах books и subscriptions вызывают соответствующие изменения в материализованном представле-
нии books_statistics.
Решение 3.1.2.b{215}.
Если вы пропустили решение{216} задачи 3.1.2.a{215}, настоятельно рекомендуется ознакомиться с ним перед тем, как продолжить чтение, т.к. многие неочевидные моменты, которые встретят в данном решении, были рассмотрены ранее.
По сравнению с предыдущей задачей{215} здесь всё будет намного проще, т.к. запрос, формирующий необходимый набор данных, не содержит выражений, подпадающих под ограничения индексированных представлений MS SQL Server и материализованных представлений Oracle.
Проблема будет только с MySQL, т.к. в нём подобных представлений нет как явления, и нам снова придётся создавать кэширующую таблицу и триггеры.
Создадим кэширующую таблицу (именно кэширующую, а не агрегирующую, как в задаче 3.1.2.a{215}, т.к. здесь мы ничего не агрегируем, а лишь сохраняем готовый результат). Код её создания можно почти полностью взять из кода создания таблицы subscritions, а для полей sb_subscriber и sb_book взять их опреде-
ления из таблицы subscribers и books.
MySQL Решение 3.1.2.b (создание кэширующей таблицы)
1CREATE TABLE `subscriptions_ready`
2(
3`sb_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
4`sb_subscriber` VARCHAR(150) NOT NULL,
5`sb_book` VARCHAR(150) NOT NULL,
6`sb_start` DATE NOT NULL,
7`sb_finish` DATE NOT NULL,
8`sb_is_active` ENUM ('Y', 'N') NOT NULL,
9CONSTRAINT `PK_subscriptions` PRIMARY KEY (`sb_id`)
10)
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 232/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Проинициализируем данные в созданной таблице:
MySQL Решение 3.1.2.b (очистка таблицы и инициализация данных)
1-- Очистка таблицы:
2TRUNCATE TABLE `subscriptions_ready`;
3
4-- Инициализация данных:
5INSERT INTO `subscriptions_ready`
6 |
|
(`sb_id`, |
7 |
|
`sb_subscriber`, |
8 |
|
`sb_book`, |
9 |
|
`sb_start`, |
10 |
|
`sb_finish`, |
11 |
|
`sb_is_active`) |
12SELECT `sb_id`,
13`s_name` AS `sb_subscriber`,
14`b_name` AS `sb_book`,
15`sb_start`,
16`sb_finish`,
17`sb_is_active`
18 FROM `books`
19JOIN `subscriptions`
20ON `b_id` = `sb_book`
21JOIN `subscribers`
22ON `sb_subscriber` = `s_id`;
Напишем триггеры, модифицирующие данные в кэширующей таблице. Источником данных являются таблицы books, subscribers и subscriptions, потому придётся создавать триггеры для всех трёх таблиц.
Поскольку MySQL версии 5.6 не позволяет создавать несколько однотипных триггеров на одной и той же таблице, перед выполнением следующего кода придётся удалить созданные в задаче 3.2.1.a{215} триггеры с таблиц books и subscriptions.
Регистрация в библиотеке новых книг и читателей никак не влияет на содержимое таблицы subscriptions, потому нет необходимости создавать INSERT- триггеры на таблицах books и subscribers — достаточно DELETE- и UPDATE- триггеров.
Обратите внимание на несколько важных моментов в представленном ниже
коде:
•внутри триггера в MySQL мы не можем явно или неявно подтверждать транзакцию, а потому не можем использовать для очистки таблицы оператор TRUNCATE (он является «нетранзакционным», и потому приводит к неявному подтверждению транзакции);
•мы не храним в нашей кэширующей таблице идентификаторы книг, и потому не можем найти и удалить только отдельные записи (искать и удалять по названию книги тоже нельзя — несколько разных книг могут иметь одинаковое название), потому мы вынуждены каждый раз очищать всю таблицу и заново наполнять её данными;
•в задаче 3.2.1.a{215} мы использовали BEFORE-триггеры, хотя могли использовать и AFTER — там это не имело значения, здесь же мы обязаны использовать только AFTER-триггеры, т.к. в противном случае в силу особенностей логики транзакций поведение MySQL отличается от ожидаемого, и информация в кэширующей таблице может не обновиться.
За исключением только что рассмотренных нюансов код тела обоих триггеров совершенно тривиален и представляет собой два запроса — на удаление всех
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 233/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
данных из таблицы и на наполнение таблицы данными на основе полученной выборки. Оба эти запроса можно выполнить совершенно отдельно от триггеров как самостоятельные SQL-конструкции.
В триггере, реагирующем на обновление информации о книге, есть проверка (строка 45) того, поменялось ли название книги. Если не поменялось, то нет необходимости обновлять закэшированные данные.
MySQL Решение 3.1.2.b (триггеры для таблицы books)
1-- Удаление старых версий триггеров
2-- (удобно в процессе разработки и отладки):
3DROP TRIGGER `upd_sbs_rdy_on_books_del`;
4DROP TRIGGER `upd_sbs_rdy_on_books_upd`;
5
6-- Переключение разделителя завершения запроса,
7-- т.к. сейчас запросом будет создание триггера,
8-- внутри которого есть свои, классические запросы:
9DELIMITER $$
10
11-- Создание триггера, реагирующего на удаление книг:
12CREATE TRIGGER `upd_sbs_rdy_on_books_del`
13AFTER DELETE
14ON `books`
15FOR EACH ROW
16BEGIN
17DELETE FROM `subscriptions_ready`;
18INSERT INTO `subscriptions_ready`
19 |
|
|
(`sb_id`, |
20 |
|
|
`sb_subscriber`, |
21 |
|
|
`sb_book`, |
22 |
|
|
`sb_start`, |
23 |
|
|
`sb_finish`, |
24 |
|
|
`sb_is_active`) |
25 |
|
SELECT |
`sb_id`, |
26 |
|
|
`s_name`, |
27 |
|
|
`b_name`, |
28 |
|
|
`sb_start`, |
29 |
|
|
`sb_finish`, |
30 |
|
|
`sb_is_active` |
31 |
|
FROM |
`books` |
32 |
|
|
JOIN `subscriptions` |
33 |
|
|
ON `b_id` = `sb_book` |
34 |
|
|
JOIN `subscribers` |
35 |
|
|
ON `sb_subscriber` = `s_id`; |
36END;
37$$
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 234/545