Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle(1)
.pdfПример 27: выборка данных с использованием кэширующих представлений и таблиц
MySQL |
Решение 3.1.2.a (триггеры для таблицы subscriptions) (продолжение) |
50-- Создание триггера, реагирующего на обновление выдачи книг:
51CREATE TRIGGER `upd_bks_sts_on_subscriptions_upd`
52BEFORE UPDATE
53ON `subscriptions`
54FOR EACH ROW
55BEGIN
56SET @delta = 0;
57
58IF ((NEW.`sb_is_active` = 'Y') AND (OLD.`sb_is_active` = 'N')) THEN
59SET @delta = -1;
60END IF;
61
62IF ((NEW.`sb_is_active` = 'N') AND (OLD.`sb_is_active` = 'Y')) THEN
63SET @delta = 1;
64END IF;
65
66UPDATE `books_statistics` SET
67`rest` = `rest` + @delta,
68`given` = `given` - @delta;
69END;
70$$
71
72-- Восстановление разделителя завершения запросов:
73DELIMITER ;
Триггеры на таблице subscriptions оказываются чуть более сложными, тем триггеры на таблице books: здесь приходится анализировать происходящее и предпринимать действия в зависимости от ситуации.
В триггере, реагирующем на добавление выдачи книг (строки 13-30) мы должны изменить значения `rest` и `given` только в том случае, если книга в добавляемой выдаче отмечена как находящаяся на руках у читателя. Изначально мы предполагаем, что это не так, и инициализируем в строке 20 переменную @delta значением 0. Если далее оказывается, что книга всё же выдана, мы изменяем значение этой переменной на 1 (строки 22-24). Таким образом, в запросе в строках 26-28 значения полей агрегирующей таблицы будут меняться на 0 (т.е. оставаться неизменными) или на 1 в зависимости от того, выдана ли книга читателю.
Абсолютно аналогичной логикой мы руководствуемся в триггере, реагирующем на удаление выдачи книги (строки 32-49).
В триггере, реагирующем на обновление выдачи книги, нам нужно рассмотреть четыре случая (из которых нас на самом деле интересуют только два последних):
•книга была на руках у читателя и там же осталась (значение `sb_is_active` было равно Y и таким же осталось);
•книга не была на руках у читателя и там же осталась (значение `sb_is_active` было равно N и таким же осталось);
•книга была на руках у читателя, и он её вернул (значение `sb_is_active` было равно Y, но поменялось на N — строки 58-60 запроса);
•книга не была на руках у читателя, но он её забрал (значение `sb_is_active` было равно N, но поменялось на Y — строки 62-64 запроса).
Очевидно, что количество выданных и оставшихся в библиотеке книг изменяется только в двух последних случаях, которые и учтены в условиях, представленных в строках 58-64. Запрос в строках 66-68 использует значение переменной @delta, изменённое этими условиями, для модификации агрегированных данных.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 220/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Проверим, как работает то, что мы создали. Будем модифицировать данные в таблицах books и subscriptions и выбирать данные из таблицы books_statistics.
Добавим две книги с количеством экземпляров 5 и 10:
MySQL Решение 3.1.2.a (проверка реакции на добавление книг)
|
1 |
INSERT INTO `books` |
||||
|
2 |
|
|
(`b_id`, |
||
|
3 |
|
|
`b_name`, |
||
|
4 |
|
|
`b_quantity`, |
||
|
5 |
|
|
`b_year`) |
||
|
6 |
VALUES |
(NULL, |
|||
|
7 |
|
|
'Новая книга 1', |
||
|
8 |
|
|
5, |
|
|
|
9 |
|
|
2001), |
|
|
|
10 |
|
|
(NULL, |
||
|
11 |
|
|
'Новая книга 2', |
||
|
12 |
|
|
10, |
|
|
|
13 |
|
|
2002) |
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
Было |
33 |
5 |
28 |
|
|
|
Стало |
48 |
5 |
43 |
|
Увеличим на пять единиц количество экземпляров книги, которой сейчас в библиотеке зарегистрировано 10 экземпляров (такая книга у нас одна):
|
MySQL |
|
|
Решение 3.1.2.a (проверка реакции на изменение количества книги) |
|||||
|
1 |
UPDATE |
`books` |
|
|
||||
|
2 |
SET |
|
`b_quantity` = `b_quantity` + 5 |
|||||
|
3 |
WHERE |
`b_quantity` = 10 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
|
Было |
|
48 |
|
5 |
43 |
|
||
|
Стало |
|
53 |
|
5 |
48 |
|
Удалим книгу, оба экземпляра которой сейчас находится на руках у читателей (книга с идентификатором 1).
MySQL |
Решение 3.1.2.a (проверка реакции на удаление книги) |
1DELETE FROM `books`
2WHERE `b_id` = 1
|
total |
given |
rest |
Было |
53 |
5 |
48 |
Стало |
51 |
3 |
48 |
Отметим, что по выдаче с идентификатором 3 книга возвращена:
|
MySQL |
|
|
|
|
Решение 3.1.2.a (проверка реакции на возврат книги) |
|||
|
1 |
UPDATE |
`subscriptions` |
||||||
|
2 |
SET |
|
`sb_is_active` = 'N' |
|||||
|
3 |
WHERE |
`sb_id` = 3 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
|
Было |
|
51 |
|
3 |
48 |
|
||
|
Стало |
|
51 |
|
2 |
49 |
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 221/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Отменим эту операцию (снова отметим книгу как невозвращённую):
|
MySQL |
|
|
|
Решение 3.1.2.a (проверка реакции на отмену возврата книги) |
||||
|
1 |
UPDATE |
`subscriptions` |
||||||
|
2 |
SET |
|
`sb_is_active` = 'Y' |
|||||
|
3 |
WHERE |
`sb_id` = 3 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
|
Было |
|
51 |
|
2 |
49 |
|
||
|
Стало |
|
51 |
|
3 |
48 |
|
Добавим в базу данных информацию о том, что читатель с идентификатором 2 взял в библиотеке книги с идентификаторами 5 и 6:
|
MySQL |
|
|
Решение 3.1.2.a (проверка реакции на выдачу книг) |
|||
|
1 |
INSERT INTO `subscriptions` |
|||||
|
2 |
|
|
|
(`sb_id`, |
||
|
3 |
|
|
|
`sb_subscriber`, |
||
|
4 |
|
|
|
`sb_book`, |
||
|
5 |
|
|
|
`sb_start`, |
||
|
6 |
|
|
|
`sb_finish`, |
||
|
7 |
|
|
|
`sb_is_active`) |
||
|
8 |
VALUES |
(NULL, |
||||
|
9 |
|
|
|
2, |
|
|
|
10 |
|
|
|
5, |
|
|
|
11 |
|
|
|
'2016-01-10', |
||
|
12 |
|
|
|
'2016-02-10', |
||
|
13 |
|
|
|
'Y'), |
||
|
14 |
|
|
|
(NULL, |
||
|
15 |
|
|
|
2, |
|
|
|
16 |
|
|
|
6, |
|
|
|
17 |
|
|
|
'2016-01-10', |
||
|
18 |
|
|
|
'2016-02-10', |
||
|
19 |
|
|
|
'Y') |
||
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
Было |
|
51 |
3 |
48 |
|
|
|
Стало |
|
51 |
5 |
46 |
|
Удалим информацию о выдаче с идентификатором 42 (книга по этой выдаче уже возвращена):
MySQL Решение 3.1.2.a (проверка реакции на удаление выдачи с возвращённой книгой)
1DELETE FROM `subscriptions`
2WHERE `sb_id` = 42
|
total |
given |
rest |
Было |
51 |
5 |
46 |
Стало |
51 |
5 |
46 |
Удалим информацию о выдаче с идентификатором 62 (книга по этой выдаче ещё не возвращена):
MySQL Решение 3.1.2.a (проверка реакции на удаление выдачи с не возвращённой книгой)
1DELETE FROM `subscriptions`
2WHERE `sb_id` = 62
|
total |
given |
rest |
Было |
51 |
5 |
46 |
Стало |
51 |
4 |
47 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 222/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Наконец, удалим все книги (что также приведёт к каскадному удалению всех выдач):
|
MySQL |
|
|
Решение 3.1.2.a (проверка реакции на удаление всех книг) |
|||
|
1 |
DELETE FROM `books` |
|||||
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
Было |
|
51 |
4 |
47 |
|
|
|
Стало |
|
0 |
0 |
0 |
|
Итак, все операции модификации данных в таблицах books и subscriptions вызывают соответствующие изменения в агрегирующей таблице books_statistics, которая в MySQL выступает в роли кэширующего представления.
Переходим к MS SQL Server. Теоретически, здесь всё должно быть хорошо, т.к. эта СУБД поддерживает т.н. индексированные представления, но если мы внимательно изучим перечень ограничений10, то придём к неутешительному выводу: придётся идти по пути MySQL и создавать агрегирующую таблицу и триггеры.
Создадим агрегирующую таблицу:
MS SQL Решение 3.1.2.a (создание агрегирующей таблицы)
1CREATE TABLE [books_statistics]
2(
3[total] INTEGER NOT NULL,
4[given] INTEGER NOT NULL,
5 |
|
[rest] INTEGER NOT NULL |
6 |
|
) |
Проинициализируем данные в созданной таблице:
MS SQL Решение 3.1.2.a (очистка таблицы и инициализация данных)
1-- Очистка таблицы:
2TRUNCATE TABLE [books_statistics];
3
4-- Инициализация данных:
5INSERT INTO [books_statistics]
6 |
|
([total], |
7 |
|
[given], |
8 |
|
[rest]) |
9SELECT ISNULL([total], 0) AS [total],
10ISNULL([given], 0) AS [given],
11ISNULL([total] - [given], 0) AS [rest]
12 |
|
FROM |
(SELECT (SELECT |
SUM([b_quantity]) |
|
13 |
|
|
FROM |
[books]) |
AS [total], |
14 |
|
|
(SELECT |
COUNT([sb_book]) |
|
15 |
|
|
FROM |
[subscriptions] |
|
16 |
|
|
WHERE |
[sb_is_active] = 'Y') AS [given]) |
|
17 |
|
|
AS [prepared_data]; |
|
До сих пор всё было совершенно идентично MySQL, но внутренняя логика работы триггеров у MS SQL Server совершенно иная, хотя нам по-прежнему придётся создать триггеры на всех трёх операциях (вставки, обновления удаления) для обеих таблиц (books и subscriptions).
10 https://msdn.microsoft.com/en-us/library/ms191432%28v=sql.110%29.aspx
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 223/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
MS SQL Решение 3.1.2.a (триггеры для таблицы books)
1-- Удаление старых версий триггеров
2-- (удобно в процессе разработки и отладки):
3DROP TRIGGER [upd_bks_sts_on_books_ins];
4DROP TRIGGER [upd_bks_sts_on_books_del];
5DROP TRIGGER [upd_bks_sts_on_books_upd];
6GO
7
8-- Создание триггера, реагирующего на добавление книг:
9CREATE TRIGGER [upd_bks_sts_on_books_ins]
10ON [books]
11AFTER INSERT
12AS
13UPDATE [books_statistics] SET
14[total] = [total] + (SELECT SUM([b_quantity])
15 |
FROM |
[inserted]); |
16UPDATE [books_statistics] SET
17[rest] = [total] - [given];
18GO
19
20-- Создание триггера, реагирующего на удаление книг:
21CREATE TRIGGER [upd_bks_sts_on_books_del]
22ON [books]
23AFTER DELETE
24AS
25UPDATE [books_statistics] SET
26[total] = [total] - (SELECT SUM([b_quantity])
27 |
|
FROM |
[deleted]), |
|
28 |
|
[given] = [given] - (SELECT |
COUNT([sb_book]) |
|
29 |
|
FROM |
[subscriptions] |
|
30 |
|
WHERE |
[sb_book] IN (SELECT |
[b_id] |
31 |
|
|
FROM |
[deleted]) |
32 |
|
AND |
[sb_is_active] = 'Y'); |
33UPDATE [books_statistics] SET
34[rest] = [total] - [given];
35GO
36
37-- Создание триггера, реагирующего на
38-- изменение количества книг:
39CREATE TRIGGER [upd_bks_sts_on_books_upd]
40ON [books]
42AFTER UPDATE
42AS
43UPDATE [books_statistics] SET
44[total] = [total] - (SELECT SUM([b_quantity])
45 |
|
FROM |
[deleted]) + (SELECT |
SUM([b_quantity]) |
46 |
|
|
FROM |
[inserted]); |
47UPDATE [books_statistics] SET
48[rest] = [total] - [given];
49GO
Основных отличия от решения для MySQL здесь два:
•тело триггера выполняется не для каждого ряда модифицируемых данных (как это происходит в MySQL), а один раз для всего набора данных — отсюда следует не обращение к отдельному полю через ключевые слова OLD и NEW, а работа с «псевдотаблицами» [deleted] (содержит информацию об удаляемых строках и старые данные обновляемых строк) и [inserted] (содержит информацию о добавляемых строках и новые данные обновляемых строк);
•MS SQL Server не позволяет в одном запросе модифицировать значения полей и сразу же использовать их новые значения — потому во всех трёх триггерах для вычисления значения поля [rest] используется отдельный запрос.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 224/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
В остальном поведение триггеров в MS SQL Server на таблице books идентично поведению соответствующих триггеров в MySQL. А в триггерах на таблице subscriptions есть существенные отличия.
MS SQL |
Решение 3.1.2.a (триггеры для таблицы subscriptions) |
1-- Удаление старых версий триггеров
2-- (удобно в процессе разработки и отладки):
3DROP TRIGGER [upd_bks_sts_on_subscriptions_ins];
4DROP TRIGGER [upd_bks_sts_on_subscriptions_del];
5DROP TRIGGER [upd_bks_sts_on_subscriptions_upd];
6GO
7
8-- Создание триггера, реагирующего на добавление выдачи книг:
9CREATE TRIGGER [upd_bks_sts_on_subscriptions_ins]
10ON [subscriptions]
11AFTER INSERT
12AS
13DECLARE @delta INT = (SELECT COUNT(*)
14 |
|
FROM |
[inserted] |
15 |
|
WHERE |
[sb_is_active] = 'Y'); |
16UPDATE [books_statistics] SET
17[rest] = [rest] - @delta,
18[given] = [given] + @delta;
19GO
20
21-- Создание триггера, реагирующего на удаление выдачи книг:
22CREATE TRIGGER [upd_bks_sts_on_subscriptions_del]
23ON [subscriptions]
24AFTER DELETE
25AS
26DECLARE @delta INT = (SELECT COUNT(*)
27 |
|
FROM |
[deleted] |
28 |
|
WHERE |
[sb_is_active] = 'Y'); |
29UPDATE [books_statistics] SET
30[rest] = [rest] + @delta,
31[given] = [given] - @delta;
32GO
33
34-- Создание триггера, реагирующего на обновление выдачи книг:
35CREATE TRIGGER [upd_bks_sts_on_subscriptions_upd]
36ON [subscriptions]
37AFTER UPDATE
38AS
39DECLARE @taken INT = (
40SELECT COUNT(*)
41 |
|
FROM |
[inserted] |
|
42 |
|
|
JOIN |
[deleted] |
43 |
|
|
ON |
[inserted].[sb_id] = [deleted].[sb_id] |
44WHERE [inserted].[sb_is_active] = 'Y'
45AND [deleted].[sb_is_active] = 'N');
46
47DECLARE @returned INT = (
48SELECT COUNT(*)
49 |
|
FROM |
[inserted] |
|
50 |
|
|
JOIN |
[deleted] |
51 |
|
|
ON |
[inserted].[sb_id] = [deleted].[sb_id] |
52WHERE [inserted].[sb_is_active] = 'N'
53AND [deleted].[sb_is_active] = 'Y');
54
55 DECLARE @delta INT = @taken - @returned;
56
57UPDATE [books_statistics] SET
58[rest] = [rest] - @delta,
59[given] = [given] + @delta;
60GO
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 225/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
ВMySQL мы вычисляли значение переменной @delta, которое могло становиться равным 0, 1, -1 в зависимости от того, как изменение в анализируемой строке должно повлиять на данные в агрегирующей таблице.
ВMS SQL Server мы должны реализовывать реакцию на изменение не одной отдельной строки, а всего набора модифицируемых строк целиком. Именно поэтому в строках 13-15 и 26-28 значение переменной @delta определяется как ко-
личество записей, удовлетворяющих условию работы триггера.
В строках 39-55 этот подход ещё больше усложняется: мы должны определить количество выданных (строки 39-45) и возвращённых (строки 47-53) книг, а затем в строке 55 мы можем определить разность полученных чисел и использовать её значение (строки 57-59) для изменения данных в агрегирующей таблице.
Снова (как и в случае с MySQL) проверим, как работает то, что мы создали. Будем модифицировать данные в таблицах books и subscriptions и выбирать данные из таблицы books_statistics.
Добавим две книги с количеством экземпляров 5 и 10:
MS SQL Решение 3.1.2.a (проверка реакции на добавление книг)
|
1 |
INSERT INTO [books] |
||||
|
2 |
|
|
([b_name], |
||
|
3 |
|
|
[b_quantity], |
||
|
4 |
|
|
[b_year]) |
||
|
5 |
VALUES |
(N'Новая книга 1', |
|||
|
6 |
|
|
5, |
|
|
|
7 |
|
|
2001), |
|
|
|
8 |
|
|
(N'Новая книга 2', |
||
|
9 |
|
|
10, |
|
|
|
10 |
|
|
2002) |
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
Было |
33 |
5 |
28 |
|
|
|
Стало |
48 |
5 |
43 |
|
Увеличим на пять единиц количество экземпляров книги, которой сейчас в библиотеке зарегистрировано 10 экземпляров (такая книга у нас одна):
|
MS SQL |
|
|
Решение 3.1.2.a (проверка реакции на изменение количества книги) |
|||||
|
1 |
UPDATE |
[books] |
|
|
||||
|
2 |
SET |
|
[b_quantity] = [b_quantity] + 5 |
|||||
|
3 |
WHERE |
[b_quantity] = 10 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
|
Было |
|
48 |
|
5 |
43 |
|
||
|
Стало |
|
53 |
|
5 |
48 |
|
Удалим книгу, оба экземпляра которой сейчас находится на руках у читателей (книга с идентификатором 1).
MS SQL |
Решение 3.1.2.a (проверка реакции на удаление книги) |
1DELETE FROM [books]
2WHERE [b_id] = 1
|
total |
given |
rest |
Было |
53 |
5 |
48 |
Стало |
51 |
3 |
48 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 226/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Отметим, что по выдаче с идентификатором 3 книга возвращена:
|
MS SQL |
|
|
|
|
Решение 3.1.2.a (проверка реакции на возврат книги) |
|||
|
1 |
UPDATE |
[subscriptions] |
||||||
|
2 |
SET |
|
[sb_is_active] = 'N' |
|||||
|
3 |
WHERE |
[sb_id] = 3 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
|
Было |
|
51 |
|
3 |
48 |
|
||
|
Стало |
|
51 |
|
2 |
49 |
|
Отменим эту операцию (снова отметим книгу как невозвращённую):
|
MS SQL |
|
|
|
Решение 3.1.2.a (проверка реакции на отмену возврата книги) |
||||
|
1 |
UPDATE |
[subscriptions] |
||||||
|
2 |
SET |
|
[sb_is_active] = 'Y' |
|||||
|
3 |
WHERE |
[sb_id] = 3 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
|
Было |
|
51 |
|
2 |
49 |
|
||
|
Стало |
|
51 |
|
3 |
48 |
|
Добавим в базу данных информацию о том, что читатель с идентификатором 2 взял в библиотеке книги с идентификаторами 5 и 6:
|
MS SQL |
|
|
Решение 3.1.2.a (проверка реакции на выдачу книг) |
|||
|
1 |
INSERT INTO [subscriptions] |
|||||
|
2 |
|
|
|
([sb_subscriber], |
||
|
3 |
|
|
|
[sb_book], |
||
|
4 |
|
|
|
[sb_start], |
||
|
5 |
|
|
|
[sb_finish], |
||
|
6 |
|
|
|
[sb_is_active]) |
||
|
7 |
VALUES |
(2, |
|
|
||
|
8 |
|
|
|
5, |
|
|
|
9 |
|
|
|
CAST(N'2016-01-10' AS DATE), |
||
|
10 |
|
|
|
CAST(N'2016-02-10' AS DATE), |
||
|
11 |
|
|
|
'Y'), |
||
|
12 |
|
|
|
(2, |
|
|
|
13 |
|
|
|
6, |
|
|
|
14 |
|
|
|
CAST(N'2016-01-10' AS DATE), |
||
|
15 |
|
|
|
CAST(N'2016-02-10' AS DATE), |
||
|
16 |
|
|
|
'Y') |
||
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
Было |
|
51 |
3 |
48 |
|
|
|
Стало |
|
51 |
5 |
46 |
|
Удалим информацию о выдаче с идентификатором 42 (книга по этой выдаче уже возвращена):
MS SQL |
Решение 3.1.2.a (проверка реакции на удаление выдачи с возвращённой книгой) |
1DELETE FROM [subscriptions]
2WHERE [sb_id] = 42
|
total |
given |
rest |
Было |
51 |
5 |
46 |
Стало |
51 |
5 |
46 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 227/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Удалим информацию о выдаче с идентификатором 62 (книга по этой выдаче ещё не возвращена):
MS SQL |
Решение 3.1.2.a (проверка реакции на удаление выдачи с не возвращённой книгой) |
1DELETE FROM [subscriptions]
2WHERE [sb_id] = 62
|
total |
given |
rest |
Было |
51 |
5 |
46 |
Стало |
51 |
4 |
47 |
Наконец, удалим все книги (что также приведёт к каскадному удалению всех выдач):
|
MS SQL |
|
|
Решение 3.1.2.a (проверка реакции на удаление всех книг) |
|||
|
1 |
DELETE FROM [books] |
|||||
|
|
|
|
|
|
|
|
|
|
|
|
total |
given |
rest |
|
|
Было |
|
51 |
4 |
47 |
|
|
|
Стало |
|
0 |
0 |
0 |
|
Итак, все операции модификации данных в таблицах books и subscriptions вызывают соответствующие изменения в агрегирующей таблице books_statistics, которая в MS SQL Server выступает в роли кэширующего представления.
Переходим к решению для Oracle.
Oracle — единственная СУБД, в которой данная задача полноценно решается с использованием материализованных представлений. Если бы мы использовали более новую или коммерческую версию Oracle, мы могли бы реализовать самый элегантный вариант — REFRESH FAST ON COMMIT, указывающий СУБД оптимальным образом обновлять данные в материализованном представлении каждый раз, когда завершается очередная транзакция, затрагивающая таблицы, из которых собираются данные. Но в Oracle 11gR2 Express Edition эта опция нам недоступна,
и вместо неё мы используем REFRESH FORCE START WITH (SYSDATE) NEXT
(SYSDATE + 1/1440), т.е. будем принудительно обновлять данные в представлении раз в минуту.
Oracle Решение 3.1.2.a
1-- Удаление старой версии материализованного представления
2-- (удобно при разработке и отладке):
3DROP MATERIALIZED VIEW "books_statistics";
4
5-- Создание материализованного представления:
6CREATE MATERIALIZED VIEW "books_statistics"
7BUILD IMMEDIATE
8REFRESH FORCE
9START WITH (SYSDATE) NEXT (SYSDATE + 1/1440)
10AS
11SELECT "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 |
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 228/545
Пример 27: выборка данных с использованием кэширующих представлений и таблиц
Выражение BUILD IMMEDIATE в строке 7 предписывает СУБД немедленно инициализировать материализованное представление данными.
Выражения в строках 8-9 описывают способ обновления данных в материализованном представлении (REFRESH FORCE — СУБД сама выбирает оптимальный способ из доступных — либо быстрое обновление, либо полное) и периодичность этой операции (START WITH (SYSDATE) NEXT (SYSDATE + 1/1440) — начать немедленно и повторять каждую 1/1440-ю часть суток, т.е. каждую минуту).
Запрос в строках 11-19 по здравому смыслу должен быть идентичен запросам, которые мы использовали в MySQL и MS SQL Server для инициализации данных в агрегирующей таблице. Но Oracle не позволяет в материализованных представлениях использовать запросы с подзапросами в секции FROM, а вот объединять данные из двух подзапросов позволяет.
Поэтому мы сформировали два подзапроса (вычисляющий общее количество книг — строки 14-15 и вычисляющий количество выданных читателям книг — строки 16-18), а затем объединили их результаты (каждый подзапрос возвращает просто по одному числу) с применением гарантированно выполняющегося условия
1 = 1.
Результат работы SQL-кода в строках 14-15 таков:
total given
33 5
Остаётся только выбрать из него значения полей "total" и "given" и вычислить на их основе значение поля "rest", что и происходит в строках 11-13.
Снова (как и в случае с MySQL и MS SQL Server) проверим, как работает то, что мы создали. Будем модифицировать данные в таблицах books и subscriptions и выбирать данные из материализованного представления books_statistics. Обратите внимание, что после каждого запроса явно выполняется подтверждение транзакции (COMMIT), чтобы исключить ситуацию, в которой Oracle будет ждать этого события и не обновит материализованное представление.
Добавим две книги с количеством экземпляров 5 и 10:
Oracle |
Решение 3.1.2.a (проверка реакции на добавление книг) |
1INSERT ALL
2INTO "books" ("b_name",
3 |
|
"b_quantity", |
4 |
|
"b_year") |
5 |
|
VALUES (N'Новая книга 1', |
6 |
|
5, |
7 |
|
2001) |
8 |
|
INTO "books" ("b_name", |
9 |
|
"b_quantity", |
10 |
|
"b_year") |
11 |
|
VALUES (N'Новая книга 2', |
|
|
|
12 |
|
10, |
13 |
2002) |
14SELECT 1 FROM "DUAL";
15COMMIT; -- И подождать минуту.
|
total |
given |
rest |
Было |
33 |
5 |
28 |
Стало |
48 |
5 |
43 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 229/545