Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
11
Добавлен:
15.01.2021
Размер:
10.35 Mб
Скачать

Пример 30: модификация данных с использованием триггеров на представлениях

Oracle

Решение 3.2.2.a (проверка работоспособности операции удаления) (продолжение)

13-- Запрос 4 (нулевое количество совпадений):

14DELETE FROM "subscriptions_with_text"

15WHERE "sb_book" = '2';

16

17-- Запрос 5 (возможно удаление одноимённых, но

18-- при этом разных книг):

19DELETE FROM "subscriptions_with_text"

20WHERE "sb_book" = N'Евгений Онегин';

Решение 3.2.2.b{257}.

Логика выборки данных в этом представлении является упрощённым вариантом решения{76} задачи 2.2.2.b{71}, а сами триггеры в сравнении с предыдущим примером — в разы более простыми.

Т.к. MySQL не позволяет создавать триггеры на представлениях, максимум, что мы можем сделать, это создать само представление, но данные через него модифицировать не получится:

MySQL Решение 3.2.2.b (создание представления)

1CREATE VIEW `books_with_genres`

2AS

3SELECT `b_id`,

4`b_name`,

5GROUP_CONCAT(`g_name`) AS `genres`

6 FROM `books`

7JOIN `m2m_books_genres` USING(`b_id`)

8JOIN `genres` USING(`g_id`)

9GROUP BY `b_id`

ВMS SQL Server код самого представления выглядит следующим образом (см. пояснения относительно логики получения нужного результата в решении{76} задачи 2.2.2.b{71}):

MS SQL Решение 3.2.2.b (создание представления)

1CREATE VIEW [books_with_genres]

2AS

3WITH [prepared_data]

4AS (SELECT [books].[b_id],

5

 

 

[b_name],

6

 

 

 

[g_name]

7

 

FROM

[books]

8

 

 

JOIN

[m2m_books_genres]

9

 

 

ON

[books].[b_id] = [m2m_books_genres].[b_id]

10

 

 

JOIN

[genres]

11

 

 

ON

[m2m_books_genres].[g_id] = [genres].[g_id]

 

 

 

 

 

12)

13SELECT [outer].[b_id],

14[outer].[b_name],

15STUFF ((SELECT DISTINCT ',' + [inner].[g_name]

16

 

 

FROM

[prepared_data] AS [inner]

17

 

 

WHERE

[outer].[b_id] = [inner].[b_id]

18

 

 

ORDER

BY ',' + [inner].[g_name]

19

 

 

FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'),

20

 

 

1, 1, '')

21

 

 

AS [genres]

 

22

 

FROM

[prepared_data] AS [outer]

 

 

 

 

 

23GROUP BY [outer].[b_id],

24[outer].[b_name]

Создадим триггер, позволяющий реализовать операцию вставки данных.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 270/545

Пример 30: модификация данных с использованием триггеров на представлениях

MS SQL Решение 3.2.2.b (создание триггера для реализации операции вставки)

1CREATE TRIGGER [books_with_genres_ins]

2ON [books_with_genres]

3INSTEAD OF INSERT

4AS

5INSERT INTO [genres]

6

 

 

([g_name])

7

 

SELECT

[genres]

8

 

FROM

[inserted];

9

 

GO

 

Да, это — всё. Через такое представление не удастся передать идентификатор жанра (в представлении нет соответствующего поля), равно как по той же причине не удастся реализовать добавление новых книг. А добавление нового жанра действительно реализуется настолько примитивно.

Переходим к решению для Oracle. Создадим представление (см. пояснения относительно логики получения нужного результата в решении{76} задачи 2.2.2.b{71}):

Oracle Решение 3.2.2.b (создание представления)

1CREATE VIEW "books_with_genres"

2AS

3SELECT "b_id", "b_name",

4UTL_RAW.CAST_TO_NVARCHAR2

5(

6

 

LISTAGG

7

 

(

8

 

UTL_RAW.CAST_TO_RAW("g_name"),

9

 

UTL_RAW.CAST_TO_RAW(N',')

10)

11WITHIN GROUP (ORDER BY "g_name")

12)

13AS "genres"

14FROM "books"

15JOIN "m2m_books_genres" USING ("b_id")

16JOIN "genres" USING ("g_id")

17GROUP BY "b_id",

18

 

"b_name"

Создадим триггер, позволяющий реализовать операцию вставки данных.

Oracle Решение 3.2.2.b (создание триггера для реализации операции вставки)

1CREATE OR REPLACE TRIGGER "books_with_genres_ins"

2INSTEAD OF INSERT ON "books_with_genres"

3FOR EACH ROW

4BEGIN

5INSERT INTO "genres"

6

 

 

("g_name")

7

 

VALUES

(:new."genres");

8

 

END;

 

Как видно из кода триггера, решение для Oracle получилось столь же примитивным в силу причин, описанных выше в решении для MS SQL Server.

Задание 3.2.2.TSK.A: создать представление, извлекающее из таблицы m2m_books_authors человекочитаемую (с названиями книг и именами авторов вместо идентификаторов) информацию, и при этом позволяющее модифицировать данные в таблице m2m_books_authors (в случае неуникальности названий книг и имён авторов в обоих случаях использовать запись с минимальным значением первичного ключа).

Задание 3.2.2.TSK.B: создать представление, показывающее список книг с их авторами, и при этом позволяющее добавлять новых авторов.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 271/545

Пример 31: обновление кэширующих таблиц и полей

Раздел 4: Использование триггеров

4.1. Агрегация данных с использованием триггеров

4.1.1. Пример 31: обновление кэширующих таблиц и полей

Дополнительным материалом к данному примеру служат решения задач, представленных в примерах 27{215}, 29{245} и 30{257}.

Задача 4.1.1.a{272}: модифицировать схему базы данных «Библиотека» таким образом, чтобы таблица subscribers хранила актуальную информацию о дате последнего визита читателя в библиотеку.

Задача 4.1.1.b{281}: создать кэширующую таблицу averages, содержащую в любой момент времени следующую актуальную информацию:

а) сколько в среднем книг находится на руках у читателя; б) за сколько в среднем по времени (в днях) читатель прочитывает книгу; в) сколько в среднем книг прочитал читатель.

Ожидаемый результат 4.1.1.a.

Таблица subscribers содержит дополнительное поле, хранящее актуальную информацию о дате последнего визита читателя в библиотеку:

s_id

s_name

s_last_visit

1

Иванов И.И.

2015-10-07

2

Петров П.П.

NULL

3

Сидоров С.С.

2014-08-03

4

Сидоров С.С.

2015-10-08

Ожидаемый результат 4.1.1.b.

Таблица averages содержит следующую актуальную в любой момент времени информацию:

books_taken days_to_read books_returned

1.2500

46.0000

1.5000

Решение 4.1.1.a{272}.

Для решения этой задачи нужно будет выполнить три шага:

модифицировать таблицу subscribers (добавив туда поле для хранения даты последнего визита читателя);

проинициализировать значения последних визитов для всех читателей;

создать триггеры для поддержания этой информации в актуальном состоянии.

Важно! В MySQL триггеры не активируются каскадными операциями, потому изменения в таблице subscriptions, вызванные удалением книг, останутся «незаметными» для триггеров на этой таблице. В задании 4.1.1.TSK.D{291} вам предлагается доработать данное решение, устранив эту проблему.

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 272/545

Пример 31: обновление кэширующих таблиц и полей

Для MySQL первые два шага выполняются с помощью следующих запросов.

MySQL Решение 4.1.1.a (модификация таблицы и инициализация данных)

1-- Модификация таблицы:

2ALTER TABLE `subscribers`

3ADD COLUMN `s_last_visit` DATE NULL DEFAULT NULL AFTER `s_name`;

4

5-- Инициализация данных:

6UPDATE `subscribers`

7LEFT JOIN (SELECT `sb_subscriber`,

8

 

 

 

MAX(`sb_start`) AS `last_visit`

9

 

 

FROM

`subscriptions`

10

 

 

GROUP

BY `sb_subscriber`) AS `prepared_data`

11

 

 

ON `s_id`

= `sb_subscriber`

12

 

SET

`s_last_visit` =

`last_visit`;

 

 

 

 

 

Поскольку значение даты последнего визита читателя зависит от информации, представленной в таблице subscriptions (конкретно — от значения поля sb_start), именно на этой таблице нам и придётся создавать триггеры.

В принципе, во всех трёх триггерах можно было использовать однотипное решение (UPDATE на основе JOIN), но для разнообразия в INSERT-триггере мы реализуем более простой вариант: проверим, оказалась ли дата добавляемой выдачи больше, чем сохранённая дата последнего визита и, если это так, обновим дату последнего визита.

В UPDATE- и DELETE-триггерах такое решение не годится: если в результате этих операций окажется, что читатель ни разу не был в библиотеке, значением даты его последнего визита должен стать NULL. Такой результат проще всего достигается с помощью UPDATE на основе JOIN.

Для операций UPDATE и DELETE критически важно использовать именно AF- TER-триггеры, т.к. BEFORE-триггеры будут работать со «старыми» данными, что приведёт к некорректному определению искомой даты.

Также обратите внимание, что в UPDATE-триггере мы должны обновлять дату последнего визита для двух потенциально разных читателей, т.к. при внесении изменения выдача может быть «передана» от одного читателя к другому (мы рассмотрим эту ситуацию в процессе проверки работоспособности полученного решения).

MySQL

Решение 4.1.1.a (создание триггеров)

1-- Удаление старых версий триггеров

2-- (удобно в процессе разработки и отладки):

3DROP TRIGGER `last_visit_on_subscriptions_ins`;

4DROP TRIGGER `last_visit_on_subscriptions_upd`;

5DROP TRIGGER `last_visit_on_subscriptions_del`;

6

7-- Переключение разделителя завершения запроса,

8-- т.к. сейчас запросом будет создание триггера,

9-- внутри которого есть свои, классические запросы:

10DELIMITER $$

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 273/545

Пример 31: обновление кэширующих таблиц и полей

MySQL Решение 4.1.1.a (создание триггеров) (продолжение)

11-- Создание триггера, реагирующего на добавление выдачи книг:

12CREATE TRIGGER `last_visit_on_subscriptions_ins`

13AFTER INSERT

14ON `subscriptions`

15FOR EACH ROW

16BEGIN

17IF (SELECT IFNULL(`s_last_visit`, '1970-01-01')

18 FROM `subscribers`

19WHERE `s_id` = NEW.`sb_subscriber`) < NEW.`sb_start`

20THEN

21UPDATE `subscribers`

22

SET

`s_last_visit` = NEW.`sb_start`

23WHERE `s_id` = NEW.`sb_subscriber`;

24END IF;

25END;

26$$

27

28-- Создание триггера, реагирующего на обновление выдачи книг:

29CREATE TRIGGER `last_visit_on_subscriptions_upd`

30AFTER UPDATE

31ON `subscriptions`

32FOR EACH ROW

33BEGIN

34UPDATE `subscribers`

35LEFT JOIN (SELECT `sb_subscriber`,

36

 

 

 

MAX(`sb_start`) AS `last_visit`

37

 

 

FROM

`subscriptions`

38

 

 

GROUP

BY `sb_subscriber`) AS `prepared_data`

39

 

 

ON `s_id` = `sb_subscriber`

40

 

SET

`s_last_visit`

= `last_visit`

41WHERE `s_id` IN (OLD.`sb_subscriber`, NEW.`sb_subscriber`);

42END;

43$$

44

45-- Создание триггера, реагирующего на удаление выдачи книг:

46CREATE TRIGGER `last_visit_on_subscriptions_del`

47AFTER DELETE

48ON `subscriptions`

49FOR EACH ROW

50BEGIN

51UPDATE `subscribers`

52LEFT JOIN (SELECT `sb_subscriber`,

53

 

 

 

MAX(`sb_start`) AS `last_visit`

54

 

 

FROM

`subscriptions`

55

 

 

GROUP

BY `sb_subscriber`) AS `prepared_data`

56

 

 

ON `s_id` = `sb_subscriber`

57

 

SET

`s_last_visit`

= `last_visit`

58WHERE `s_id` = OLD.`sb_subscriber`;

59END;

60$$

61

62-- Восстановление разделителя завершения запросов:

63DELIMITER ;

Проверим работоспособность полученного решения. Будем изменять данные в таблице subscriptions и отслеживать изменения данных в таблице subscribers.

Для начала добавим выдачу книги читателю с идентификатором 2 (ранее он никогда не был в библиотеке):

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 274/545

Пример 31: обновление кэширующих таблиц и полей

MySQL Решение 4.1.1.a (проверка работоспособности)

 

1

INSERT INTO `subscriptions`

 

2

VALUES

(200,

 

 

3

 

2,

 

 

 

4

 

1,

 

 

 

5

 

'2019-01-12',

 

 

6

 

'2019-02-12',

 

 

7

 

'N')

 

 

 

 

 

 

 

s_id

s_name

 

s_last_visit

 

 

1

Иванов И.И.

2015-10-07

 

 

2

Петров П.П.

2019-01-12

 

 

3

Сидоров С.С.

2014-08-03

 

 

4

Сидоров С.С.

2015-10-08

 

Теперь эмулируем ситуацию «книга ошибочно записана на другого читателя» и изменим идентификатор читателя в только что добавленной выдаче с 2 на 1. NULL-значение даты последнего визита Петрова П.П. корректно восстановилось:

 

MySQL

 

Решение 4.1.1.a (проверка работоспособности)

 

1

UPDATE

`subscriptions`

 

2

SET

`sb_subscriber` = 1

 

3

WHERE

`sb_id` = 200

 

 

 

 

 

 

 

 

 

s_id

 

 

 

s_name

s_last_visit

 

 

1

 

Иванов И.И.

2019-01-12

 

 

2

 

Петров П.П.

NULL

 

 

3

 

Сидоров С.С.

2014-08-03

 

 

4

 

Сидоров С.С.

2015-10-08

 

Снова добавим выдачу книги Петрову П.П.:

 

MySQL

 

Решение 4.1.1.a (проверка работоспособности)

 

1

INSERT INTO `subscriptions`

 

2

VALUES

(201,

 

 

3

 

 

 

2,

 

 

 

4

 

 

 

1,

 

 

 

5

 

 

 

'2020-01-12',

 

 

6

 

 

 

'2020-02-12',

 

 

7

 

 

 

'N')

 

 

 

 

 

 

 

 

 

s_id

 

 

s_name

 

s_last_visit

 

 

1

 

Иванов И.И.

2019-01-12

 

 

2

 

Петров П.П.

2020-01-12

 

 

3

 

Сидоров С.С.

2014-08-03

 

 

4

 

Сидоров С.С.

2015-10-08

 

Изменим значение даты ранее откорректированной выдачи книги (которую мы переписали с Петрова П.П. на Иванова И.И.):

 

MySQL

 

Решение 4.1.1.a (проверка работоспособности)

 

1

UPDATE

`subscriptions`

 

2

SET

`sb_start` = '2018-01-12'

 

3

WHERE

`sb_id` = 200

 

 

 

 

 

 

 

 

s_id

 

 

s_name

s_last_visit

 

 

1

 

Иванов И.И.

2018-01-12

 

 

2

 

Петров П.П.

2020-01-12

 

 

3

 

Сидоров С.С.

2014-08-03

 

 

4

 

Сидоров С.С.

2015-10-08

 

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 275/545

Пример 31: обновление кэширующих таблиц и полей

Удалим эту выдачу:

MySQL Решение 4.1.1.a (проверка работоспособности)

1DELETE FROM `subscriptions`

2WHERE `sb_id` = 200

s_id

s_name

s_last_visit

1

Иванов И.И.

2015-10-07

2

Петров П.П.

2020-01-12

3

Сидоров С.С.

2014-08-03

4

Сидоров С.С.

2015-10-08

Удалим единственную выдачу книги Петрову П.П.:

MySQL Решение 4.1.1.a (проверка работоспособности)

1DELETE FROM `subscriptions`

2WHERE `sb_id` = 201

s_id

s_name

s_last_visit

1

Иванов И.И.

2015-10-07

2

Петров П.П.

NULL

3

Сидоров С.С.

2014-08-03

4

Сидоров С.С.

2015-10-08

Итак, решение для MySQL полностью готово и корректно работает. Но прежде, чем перейти к решению для MS SQL Server проведём небольшое исследование, наглядно демонстрирующее ответ на вопрос о том, «отменяется ли действие BEFORE-триггера в случае ошибки в процессе выполнения операции».

Исследование 4.4.1.EXP.A. Будут ли аннулированы изменения данных, вызванные работой BEFORE-триггера, если операция, активировавшая этот триггер, не сможет завершиться успешно?

Изменим вид INSERT-триггера с AFTER на BEFORE:

MySQL

Исследование 4.1.1.a (изменение типа триггера)

1 DROP TRIGGER `last_visit_on_subscriptions_ins`; 2

3 DELIMITER $$

4

5CREATE TRIGGER `last_visit_on_subscriptions_ins`

6BEFORE INSERT

7ON `subscriptions`

8FOR EACH ROW

9BEGIN

10IF (SELECT IFNULL(`s_last_visit`, '1970-01-01')

11 FROM `subscribers`

12WHERE `s_id` = NEW.`sb_subscriber`) < NEW.`sb_start`

13THEN

14UPDATE `subscribers`

15

 

SET

`s_last_visit` = NEW.`sb_start`

16WHERE `s_id` = NEW.`sb_subscriber`;

17END IF;

18END;

19$$

20

21 DELIMITER ;

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 276/545

Пример 31: обновление кэширующих таблиц и полей

Выполним последовательно добавление двух выдач книг с разными датами, но одинаковыми значениями первичных ключей:

MySQL

 

Исследование 4.1.1.a (вставка данных)

1

INSERT INTO `subscriptions`

2

VALUES

(500,

3

 

 

2,

4

 

 

1,

5

 

 

'2020-01-12',

6

 

 

'2020-02-12',

7

 

 

'N');

8

 

 

 

9

INSERT INTO `subscriptions`

10

VALUES

(500,

11

 

 

2,

12

 

 

1,

13

 

 

'2021-01-12',

14

 

 

'2021-02-12',

15

 

 

'N');

Проверим данные в таблице subscribers:

s_id

s_name

s_last_visit

1

Иванов И.И.

2015-10-07

2

Петров П.П.

2020-01-12

3

Сидоров С.С.

2014-08-03

4

Сидоров С.С.

2015-10-08

Итак, изменения аннулируются, если операция не может быть завершена успешно. В противном случае значением даты последнего визита Петрова П.П.

было бы 2021-01-12.

Переходим к решению поставленной задачи для MS SQL Server. Модифицируем таблицу subscribers и проинициализируем добавленное поле данными.

MS SQL Решение 4.1.1.a (модификация таблицы и инициализация данных)

1-- Модификация таблицы:

2ALTER TABLE [subscribers]

3ADD [s_last_visit] DATE NULL DEFAULT NULL;

4

5-- Инициализация данных:

6UPDATE [subscribers]

7

 

SET

[s_last_visit] =

[last_visit]

8

 

FROM

[subscribers]

 

9

 

 

LEFT JOIN (SELECT

[sb_subscriber],

10

 

 

 

MAX([sb_start]) AS [last_visit]

11

 

 

FROM

[subscriptions]

12

 

 

GROUP

BY [sb_subscriber]) AS [prepared_data]

13

 

 

ON [s_id]

= [sb_subscriber];

MS SQL Server поддерживает очень удобный синтаксис создания триггера сразу на нескольких операциях, потому (в отличие от решения для MySQL) мы используем одинаковый код тела триггера для всех трёх случаев (INSERT, UPDATE,

DELETE):

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 277/545

Пример 31: обновление кэширующих таблиц и полей

MS SQL

Решение 4.1.1.a (создание триггеров)

1CREATE TRIGGER [last_visit_on_subscriptions_ins_upd_del]

2ON [subscriptions]

3AFTER INSERT, UPDATE, DELETE

4AS

5UPDATE [subscribers]

6

 

SET

[s_last_visit] =

[last_visit]

7

 

FROM

[subscribers]

 

8

 

 

LEFT JOIN (SELECT

[sb_subscriber],

9

 

 

 

MAX([sb_start]) AS [last_visit]

10

 

 

FROM

[subscriptions]

11

 

 

GROUP

BY [sb_subscriber]) AS [prepared_data]

12

 

 

ON [s_id] = [sb_subscriber];

В корректности работы полученного решения вы можете убедиться, выполнив следующие запросы (они выполнены пошагово с пояснениями и показом результатов в решении для MySQL):

MS SQL Решение 4.1.1.a (запросы для проверки работоспособности)

1 SET IDENTITY_INSERT [subscriptions] ON;

2

3-- Добавление выдачи книги читателю с идентификатором 2

4-- (ранее он никогда не был в библиотеке):

5INSERT INTO [subscriptions]

6

 

 

([sb_id],

7

 

 

[sb_subscriber],

8

 

 

[sb_book],

9

 

 

[sb_start],

10

 

 

[sb_finish],

11

 

 

[sb_is_active])

12

 

VALUES

(200,

13

 

 

2,

14

 

 

1,

15

 

 

'2019-01-12',

16

 

 

'2019-02-12',

17

 

 

'N');

18

 

 

 

19-- Изменение идентификатора читателя в только что

20-- добавленной выдаче с 2 на 1:

21UPDATE [subscriptions]

22

 

SET

[sb_subscriber] = 1

23

 

WHERE

[sb_id] = 200;

24

 

 

 

25-- Ещё одна выдача книги Петрову П.П.

26-- (идентификатор читателя = 2):

27INSERT INTO [subscriptions]

28

 

 

([sb_id],

29

 

 

[sb_subscriber],

30

 

 

[sb_book],

31

 

 

[sb_start],

32

 

 

[sb_finish],

33

 

 

[sb_is_active])

34

 

VALUES

(201,

 

 

 

 

35

 

 

2,

36

 

 

1,

37

 

 

'2020-01-12',

38

 

 

'2020-02-12',

39

 

 

'N');

40

 

 

 

 

 

 

 

41-- Изменение значения даты ранее откорректированной

42-- выдачи книги (которую переписали с Петрова П.П.

43-- на Иванова И.И.):

44UPDATE [subscriptions]

45

 

SET

[sb_start] = '2018-01-12'

46

 

WHERE

[sb_id] = 200;

 

 

 

 

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 278/545

Пример 31: обновление кэширующих таблиц и полей

MS SQL Решение 4.1.1.a (запросы для проверки работоспособности) (продолжение)

47-- Удаление этой откорректированной выдачи:

48DELETE FROM [subscriptions]

49WHERE [sb_id] = 200;

50

51-- Удаление единственной выдачи Петрову П.П.:

52DELETE FROM [subscriptions]

53WHERE [sb_id] = 201;

54

55 SET IDENTITY_INSERT [subscriptions] OFF;

Переходим к решению для Oracle, которое отличается от решения для MS SQL Server только синтаксическими особенностями реализации той же логики:

Oracle Решение 4.1.1.a (модификация таблицы и инициализация данных)

1-- Модификация таблицы:

2ALTER TABLE "subscribers"

3ADD ("s_last_visit" DATE DEFAULT NULL NULL);

4

5-- Инициализация данных:

6UPDATE "subscribers" "outer"

7

 

SET

"s_last_visit" =

 

8

 

 

(

 

 

9

 

 

SELECT

"last_visit"

10

 

 

FROM

"subscribers"

11

 

 

LEFT JOIN (SELECT

"sb_subscriber",

12

 

 

 

 

MAX("sb_start") AS "last_visit"

13

 

 

 

FROM

"subscriptions"

14

 

 

 

GROUP BY

"sb_subscriber") "prepared_data"

15

 

 

ON

"s_id" =

"sb_subscriber"

16

 

 

WHERE "outer"."s_id" = "sb_subscriber");

Oracle Решение 4.1.1.a (создание триггеров)

1CREATE TRIGGER "last_visit_on_scs_ins_upd_del"

2AFTER INSERT OR UPDATE OR DELETE

3ON "subscriptions"

4BEGIN

5UPDATE "subscribers" "outer"

6

 

SET

"s_last_visit" =

7

 

 

(

 

8

 

 

SELECT

"last_visit"

9

 

 

FROM

"subscribers"

10

 

LEFT JOIN (SELECT

"sb_subscriber",

11

 

 

 

MAX("sb_start") AS "last_visit"

12

 

 

FROM

"subscriptions"

13

 

 

GROUP BY

"sb_subscriber") "prepared_data"

14

 

ON

"s_id" =

"sb_subscriber"

15WHERE "outer"."s_id" = "sb_subscriber");

16END;

Вданном решении мы использовали возможность Oracle создавать т.н. «триггеры уровня выражения» (statement level triggers), работающие аналогично триггерам MS SQL Server: такой триггер активируется после выполнения всей операции один раз, а не для каждого модифицируемого ряда отдельно, как это происходит, например, в MySQL, где поддерживаются только «триггеры уровня записи» (row level triggers), активирующиеся отдельно для каждого модифицируемого ряда.

Вкорректности работы полученного решения вы можете убедиться, выполнив следующие запросы (они выполнены пошагово с пояснениями и показом результатов в решении для MySQL):

Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 279/545