Материал: Using_MySql,_MS_SQL_Server_and_Oracle(1)

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

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

Источник: https://studfile.net/preview/16418462/