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

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

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

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