Бази даних-20210115T104840Z-001 / Реферат на тему _Современные СУБД_ / Using_MySql,_MS_SQL_Server_and_Oracle(1)
.pdfПример 32: обеспечение консистентности данных
MS SQL Решение 4.1.2.a (триггеры для таблицы subscriptions)
1-- Реакция на обновление выдачи книги:
2CREATE TRIGGER [s_has_books_on_subscriptions_upd]
3ON [subscriptions]
4AFTER UPDATE
5AS
6-- (Это, фактически, -- код DELETE-триггера):
7UPDATE [subscribers]
8 |
|
SET |
[s_books] = [s_books] - [s_old_books] |
|
9 |
|
FROM |
[subscribers] |
|
10 |
|
|
JOIN (SELECT |
[sb_subscriber], |
11 |
|
|
|
COUNT([sb_id]) AS [s_old_books] |
12 |
|
|
FROM |
[deleted] |
13 |
|
|
|
WHERE [sb_is_active] = 'Y' |
14 |
|
|
GROUP |
BY [sb_subscriber]) AS [prepared_data] |
|
|
|
|
|
15ON [s_id] = [sb_subscriber];
16-- (Это, фактически, -- код INSERT-триггера):
17UPDATE [subscribers]
18 |
|
SET |
[s_books] = [s_books] + [s_new_books] |
|
19 |
|
FROM |
[subscribers] |
|
20 |
|
|
JOIN (SELECT |
[sb_subscriber], |
21 |
|
|
|
COUNT([sb_id]) AS [s_new_books] |
22 |
|
|
FROM |
[inserted] |
23 |
|
|
|
WHERE [sb_is_active] = 'Y' |
24 |
|
|
GROUP |
BY [sb_subscriber]) AS [prepared_data] |
25ON [s_id] = [sb_subscriber];
26GO
MS SQL Решение 4.1.2.a (проверка работоспособности)
1 |
|
SET IDENTITY_INSERT [subscriptions] ON; |
2 |
|
|
|
|
|
3-- Добавим Иванову И.И. две активных выдачи,
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 |
|
|
1, |
14 |
|
|
3, |
15 |
|
|
'2011-01-12', |
16 |
|
|
'2011-02-12', |
17 |
|
|
'Y'), |
18 |
|
|
(201, |
19 |
|
|
1, |
20 |
|
|
4, |
21 |
|
|
'2011-01-12', |
22 |
|
|
'2011-02-12', |
23 |
|
|
'Y'), |
24 |
|
|
(202, |
25 |
|
|
2, |
26 |
|
|
3, |
27 |
|
|
'2011-01-12', |
28 |
|
|
'2011-02-12', |
29 |
|
|
'Y'), |
30 |
|
|
(203, |
31 |
|
|
2, |
32 |
|
|
4, |
33 |
|
|
'2011-01-12', |
34 |
|
|
'2011-02-12', |
35 |
|
|
'N'); |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 300/545
Пример 32: обеспечение консистентности данных
MS SQL Решение 4.1.2.a (проверка работоспособности) (продолжение)
36-- Удалим добавленные выдачи:
37DELETE FROM [subscriptions]
38WHERE [sb_id] IN (200, 201, 202, 203);
39
40-- Проверим реакцию на обновление выдач книг.
41-- Сначала добавим две выдачи:
42INSERT INTO [subscriptions]
43 |
|
|
([sb_id], |
44 |
|
|
[sb_subscriber], |
45 |
|
|
[sb_book], |
46 |
|
|
[sb_start], |
47 |
|
|
[sb_finish], |
48 |
|
|
[sb_is_active]) |
49 |
|
VALUES |
(300, |
50 |
|
|
1, |
51 |
|
|
3, |
52 |
|
|
'2011-01-12', |
53 |
|
|
'2011-02-12', |
54 |
|
|
'Y'), |
55 |
|
|
(301, |
56 |
|
|
1, |
57 |
|
|
4, |
58 |
|
|
'2011-01-12', |
59 |
|
|
'2011-02-12', |
60 |
|
|
'Y'); |
61 |
|
|
|
62-- Не меняя идентификатор читателя сделаем выдачи неактивными:
63UPDATE [subscriptions]
64 |
|
SET |
[sb_is_active] = |
'N' |
65 |
|
WHERE |
[sb_id] IN (300, |
301); |
66 |
|
|
|
|
67-- Не меняя идентификатор читателя сделаем выдачи снова активными:
68UPDATE [subscriptions]
69 |
|
SET |
[sb_is_active] = |
'Y' |
70 |
|
WHERE |
[sb_id] IN (300, |
301); |
71 |
|
|
|
|
72-- Изменим идентификатор читателя, не меняя состояние активности выдач:
73UPDATE [subscriptions]
74 |
|
SET |
[sb_subscriber] = 2 |
75 |
|
WHERE |
[sb_id] IN (300, 301); |
76 |
|
|
|
77-- Изменим идентификатор читателя и сделаем выдачи неактивными:
78UPDATE [subscriptions]
79 |
|
SET |
[sb_subscriber] = 1, |
80[sb_is_active] = 'N'
81WHERE [sb_id] IN (300, 301);
82
83-- Изменим идентификатор читателя и сделаем выдачи активными:
84UPDATE [subscriptions]
85 |
|
SET |
[sb_subscriber] = 2, |
86[sb_is_active] = 'Y'
87WHERE [sb_id] IN (300, 301);
88
89-- Удаление книги с идентификатором 1 (выдана по одному экземпляру
90-- Петрову и обоим Сидоровым):
91DELETE FROM [books]
92WHERE [b_id] = 1;
93 |
|
94 |
SET IDENTITY_INSERT [subscriptions] OFF; |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 301/545
Пример 32: обеспечение консистентности данных
Переходим к решению поставленной задачи для Oracle. Модифицируем таблицу subscribers и проинициализируем добавленное поле данными.
MS SQL Решение 4.1.2.a (модификация таблицы и инициализация данных)
1-- Модификация таблицы:
2ALTER TABLE "subscribers"
3ADD ("s_books" INT DEFAULT 0 NOT NULL);
4
5-- Инициализация данных:
6UPDATE "subscribers"
7 |
|
SET |
"s_books" |
= NVL( |
|
8 |
|
|
(SELECT |
COUNT("sb_id") AS |
"s_has_books" |
9 |
|
|
FROM |
"subscriptions" |
|
10 |
|
|
WHERE |
"sb_is_active" = 'Y' |
|
11 |
|
|
AND |
"sb_subscriber" = |
"s_id" |
12 |
|
|
GROUP BY |
"sb_subscriber"), |
0); |
Обратите внимание: из-за синтаксических особенностей Oracle, вынуждающих нас писать такой запрос на обновление, приходится применять функцию NVL, потому что коррелирующий подзапрос в строках 7-16 выполнится для каждого ряда таблицы subscribers, и в некоторых случаях вернёт NULL.
Несмотря на то, что Oracle (как и MS SQL Server) поддерживает триггеры уровня выражения, мы не можем использовать представленную в решении для MS SQL логику, т.к. в Oracle нет псевдотаблиц inserted и updated. Нам придётся идти по пути решения для MySQL и использовать триггеры уровня записи.
Oracle Решение 4.1.2.a (триггеры для таблицы subscriptions)
1-- Реакция на добавление выдачи книги:
2CREATE OR REPLACE TRIGGER "s_has_books_on_sbps_ins"
3AFTER INSERT
4ON "subscriptions"
5FOR EACH ROW
6BEGIN
7IF (:new."sb_is_active" = 'Y') THEN
8UPDATE "subscribers"
9 |
|
SET |
"s_books" = "s_books" + 1 |
|
|
|
|
10WHERE "s_id" = :new."sb_subscriber";
11END IF;
12END;
13
14-- Реакция на удаление выдачи книги:
15CREATE OR REPLACE TRIGGER "s_has_books_on_sbps_del"
16AFTER DELETE
17ON "subscriptions"
18FOR EACH ROW
19BEGIN
20IF (:old."sb_is_active" = 'Y') THEN
21UPDATE "subscribers"
22 |
|
SET |
"s_books" = "s_books" - 1 |
23WHERE "s_id" = :old."sb_subscriber";
24END IF;
25END;
ВUPDATE-триггере мы также используем один в один тот же самый код, который был использован в решении для MySQL (там же были рассмотрены и показаны графически все ситуации, которые должен учитывать данный триггер).
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 302/545
Пример 32: обеспечение консистентности данных
Oracle Решение 4.1.2.a (триггеры для таблицы subscriptions)
1-- Реакция на обновление выдачи книги:
2CREATE OR REPLACE TRIGGER "s_has_books_on_sbps_upd"
3AFTER UPDATE
4ON "subscriptions"
5FOR EACH ROW
6BEGIN
7-- A) Читатель тот же, Y -> N
8IF ((:old."sb_subscriber" = :new."sb_subscriber") AND
9(:old."sb_is_active" = 'Y') AND
10(:new."sb_is_active" = 'N')) THEN
11UPDATE "subscribers"
12 |
SET |
"s_books" = "s_books" - 1 |
13WHERE "s_id" = :old."sb_subscriber";
14END IF;
15
16-- B) Читатель тот же, N -> Y
17IF ((:old."sb_subscriber" = :new."sb_subscriber") AND
18(:old."sb_is_active" = 'N') AND
19(:new."sb_is_active" = 'Y')) THEN
20UPDATE "subscribers"
21 |
SET |
"s_books" = "s_books" + 1 |
22WHERE "s_id" = :old."sb_subscriber";
23END IF;
24
25-- C) Читатели разные, Y -> Y
26IF ((:old."sb_subscriber" != :new."sb_subscriber") AND
27(:old."sb_is_active" = 'Y') AND
28(:new."sb_is_active" = 'Y')) THEN
29UPDATE "subscribers"
30 |
|
SET |
"s_books" = "s_books" - 1 |
31WHERE "s_id" = :old."sb_subscriber";
32UPDATE "subscribers"
33 |
|
SET |
"s_books" = "s_books" + 1 |
34WHERE "s_id" = :new."sb_subscriber";
35END IF;
36
37-- D) Читатели разные, Y -> N
38IF ((:old."sb_subscriber" != :new."sb_subscriber") AND
39(:old."sb_is_active" = 'Y') AND
40(:new."sb_is_active" = 'N')) THEN
41UPDATE "subscribers"
42 |
|
SET |
"s_books" = "s_books" - 1 |
43WHERE "s_id" = :old."sb_subscriber";
44END IF;
45
46-- E) Читатели разные, N -> Y
47IF ((:old."sb_subscriber" != :new."sb_subscriber") AND
48(:old."sb_is_active" = 'N') AND
49(:new."sb_is_active" = 'Y')) THEN
50UPDATE "subscribers"
51 |
|
SET |
"s_books" = "s_books" + 1 |
52WHERE "s_id" = :new."sb_subscriber";
53END IF;
54END;
Витоге код триггеров для Oracle получился полностью идентичным коду триггеров для MySQL, потому и запросы для проверки работоспособности полученного решения также совпадают для обеих СУБД.
См. код самих запросов ниже, а логика их работы с пояснением и демонстрацией изменения содержимого таблицы subscribers представлена в решении для
MySQL.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 303/545
Пример 32: обеспечение консистентности данных
Oracle Решение 4.1.2.a (проверка работоспособности)
1 ALTER TRIGGER "TRG_subscriptions_sb_id" DISABLE; 2
3-- Добавим Иванову И.И. активную выдачу, а Петрову П.П. неактивную:
4INSERT INTO "subscriptions"
5 |
|
VALUES |
(200, |
6 |
|
|
1, |
7 |
|
|
1, |
8 |
|
|
TO_DATE('2011-01-12', 'YYYY-MM-DD'), |
9 |
|
|
TO_DATE('2011-02-12', 'YYYY-MM-DD'), |
10 |
|
|
'Y'); |
11 |
|
INSERT INTO "subscriptions" |
|
12 |
|
VALUES |
(201, |
13 |
|
|
2, |
14 |
|
|
1, |
15 |
|
|
TO_DATE('2011-01-12', 'YYYY-MM-DD'), |
16 |
|
|
TO_DATE('2011-02-12', 'YYYY-MM-DD'), |
17 |
|
|
'N'); |
18 |
|
|
|
19-- Удалим добавленные выдачи:
20DELETE FROM "subscriptions"
21WHERE "sb_id" IN ( 200, 201 );
22
23-- Проверим реакцию на обновление выдач книг. Сначала добавим выдачу:
24INSERT INTO "subscriptions"
25 |
|
VALUES |
(300, |
26 |
|
|
1, |
27 |
|
|
1, |
28 |
|
|
TO_DATE('2011-01-12', 'YYYY-MM-DD'), |
29 |
|
|
TO_DATE('2011-02-12', 'YYYY-MM-DD'), |
30 |
|
|
'Y'); |
31 |
|
|
|
32-- A) Не меняя идентификатор читателя сделаем выдачу неактивной:
33UPDATE "subscriptions"
34 |
|
SET |
"sb_is_active" |
= 'N' |
35 |
|
WHERE |
"sb_id" = 300; |
|
36 |
|
|
|
|
37-- B) Не меняя идентификатор читателя сделаем выдачу снова активной:
38UPDATE "subscriptions"
39 |
|
SET |
"sb_is_active" |
= 'Y' |
40 |
|
WHERE |
"sb_id" = 300; |
|
41 |
|
|
|
|
42-- C) Изменим идентификатор читателя, не меняя состояние активности выдачи:
43UPDATE "subscriptions"
44 |
|
SET |
"sb_subscriber" = 2 |
45 |
|
WHERE |
"sb_id" = 300; |
46 |
|
|
|
47-- D) Изменим идентификатор читателя и сделаем выдачу неактивной:
48UPDATE "subscriptions"
49 SET |
"sb_subscriber" = 1, |
50"sb_is_active" = 'N'
51WHERE "sb_id" = 300;
52
53-- E) Изменим идентификатор читателя и сделаем выдачу активной:
54UPDATE "subscriptions"
55 |
|
SET |
"sb_subscriber" = 2, |
56"sb_is_active" = 'Y'
57WHERE "sb_id" = 300;
58
59-- Удалим книгу с id = 1 (выдана по одной штуке Петрову и обоим Сидоровым):
60DELETE FROM [books]
61WHERE [b_id] = 1;
62 63 ALTER TRIGGER "TRG_subscriptions_sb_id" ENABLE;
Итак, решение данной задачи получено и проверено для всех трёх СУБД.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 304/545
Пример 32: обеспечение консистентности данных
Решение 4.1.2.b{292}.
Как и в решении{292} задачи 4.1.2.a{292} здесь нужно будет выполнить те же самые действия — модифицировать таблицу, проинициализировать данные, создать триггеры. И даже код триггеров будет чем-то похож на рассмотренные ранее решения.
Традиционно начинаем с решения для MySQL: модифицируем таблицу и проинициализируем данные.
MySQL Решение 4.1.2.b (модификация таблицы и инициализация данных)
1-- Модификация таблицы:
2ALTER TABLE `genres`
3ADD COLUMN `g_books` INT(11) NOT NULL DEFAULT 0 AFTER `g_name`;
4
5-- Инициализация данных:
6UPDATE `genres`
7JOIN (SELECT `g_id`,
8 |
|
|
|
COUNT(`b_id`) |
AS `g_has_books` |
9 |
|
|
FROM |
`m2m_books_genres` |
|
10 |
|
|
GROUP |
BY `g_id`) AS |
`prepared_data` |
11 |
|
|
USING (`g_id`) |
|
|
12 |
|
SET |
`g_books` = `g_has_books`; |
|
Код всех трёх триггеров будет предельно прост: в INSERT-триггере мы увеличиваем счётчик книг у соответствующего жанра, в DELETE-триггере — уменьшаем, в UPDATE-триггере уменьшаем «старому» жанру и увеличиваем «новому» жанру. Никаких дополнительных проверок и ухищрений здесь не требуется.
MySQL Решение 4.1.2.b (триггеры для таблицы m2m_books_genres)
1 DELIMITER $$
2
3-- Реакция на добавление связи между книгами и жанрами:
4CREATE TRIGGER `g_has_books_on_m2m_b_g_ins`
5AFTER INSERT
6ON `m2m_books_genres`
7FOR EACH ROW
8BEGIN
9UPDATE `genres`
10 |
|
SET |
`g_books` = `g_books` + 1 |
11WHERE `g_id` = NEW.`g_id`;
12END;
13$$
14
15-- Реакция на обновление связи между книгами и жанрами:
16CREATE TRIGGER `g_has_books_on_m2m_b_g_upd`
17AFTER UPDATE
18ON `m2m_books_genres`
19FOR EACH ROW
20BEGIN
21UPDATE `genres`
22 |
SET |
`g_books` = `g_books` - 1 |
23WHERE `g_id` = OLD.`g_id`;
24UPDATE `genres`
25 |
SET |
`g_books` = `g_books` + 1 |
26WHERE `g_id` = NEW.`g_id`;
27END;
28$$
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 305/545
Пример 32: обеспечение консистентности данных
MySQL Решение 4.1.2.b (триггеры для таблицы m2m_books_genres) (продолжение)
29-- Реакция на удаление связи между книгами и жанрами:
30CREATE TRIGGER `g_has_books_on_m2m_b_g_del`
31AFTER DELETE
32ON `m2m_books_genres`
33FOR EACH ROW
34BEGIN
35UPDATE `genres`
36 |
|
SET |
`g_books` = `g_books` - 1 |
37WHERE `g_id` = OLD.`g_id`;
38END;
39$$
40
41 DELIMITER ;
Поскольку в MySQL триггеры не активируются каскадными операциями, удаление книги (которое приведёт к удалению всех её связей со всеми жанрами) останется незаметным для триггеров на таблице m2m_books_genres. Потому мы должны создать триггер на таблице books, учитывающий соответствующую ситуацию.
Каждая книга связана с каждым жанром не более одного раза, потому при удалении любой книги нужно на единицу уменьшить счётчик книг у каждого из жанров, с которыми она связана.
MySQL Решение 4.1.2.b (триггер для таблицы books)
1 DELIMITER $$
2
3-- Реакция на удаление книги:
4CREATE TRIGGER `g_has_books_on_books_del`
5BEFORE DELETE
6ON `books`
7FOR EACH ROW
8BEGIN
9UPDATE `genres`
10 |
|
SET |
`g_books` |
= `g_books` - 1 |
|
11 |
|
WHERE |
`g_id` IN |
(SELECT |
`g_id` |
12 |
|
|
|
FROM |
`m2m_books_genres` |
13 |
|
|
|
WHERE |
`b_id` = OLD.`b_id`); |
14END;
15$$
16
17 DELIMITER ;
Проверим корректность полученного решения. Будем модифицировать данные в таблицах m2m_books_genres и books и проверять изменения в таблице genres.
Исходное состояние таблицы genres:
g_id |
g_name |
g_books |
1 |
Поэзия |
2 |
2 |
Программирование |
3 |
3 |
Психология |
1 |
4 |
Наука |
0 |
5 |
Классика |
4 |
6 |
Фантастика |
1 |
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 306/545
Пример 32: обеспечение консистентности данных
Добавим две связи к жанру «Наука» (идентификатор жанра равен 4):
MySQL Решение 4.1.2.b (проверка работоспособности)
|
1 |
INSERT INTO `m2m_books_genres` |
|||
|
2 |
|
(`b_id`, |
|
|
|
3 |
|
`g_id`) |
|
|
|
4 |
VALUES |
(1, 4), |
|
|
|
5 |
|
(2, 4) |
|
|
|
|
|
|
|
|
|
g_id |
g_name |
g_books |
|
|
|
1 |
Поэзия |
|
2 |
|
|
2 |
Программирование |
3 |
|
|
|
3 |
Психология |
1 |
|
|
|
4 |
Наука |
|
2 |
|
|
5 |
Классика |
|
4 |
|
|
6 |
Фантастика |
1 |
|
Изменим в этих связях значения идентификаторов книг, не меняя значения идентификаторов жанров:
MySQL Решение 4.1.2.b (проверка работоспособности)
|
1 |
UPDATE |
`m2m_books_genres` |
|||
|
2 |
SET |
`b_id` = |
3 |
|
|
|
3 |
WHERE |
`b_id` = |
1 |
|
|
|
4 |
AND |
`g_id` = |
4; |
|
|
|
5 |
|
|
|
|
|
|
6 |
UPDATE |
`m2m_books_genres` |
|||
|
7 |
SET |
`b_id` = |
4 |
|
|
|
8 |
WHERE |
`b_id` = |
2 |
|
|
|
9 |
AND |
`g_id` = |
4; |
|
|
|
|
|
|
|
|
|
|
g_id |
|
g_name |
|
g_books |
|
|
1 |
Поэзия |
|
2 |
|
|
|
2 |
Программирование |
3 |
|
||
|
3 |
Психология |
|
1 |
|
|
|
4 |
Наука |
|
2 |
|
|
|
5 |
Классика |
|
4 |
|
|
|
6 |
Фантастика |
|
1 |
|
Изменим в этих связях значения идентификаторов жанров, не меняя значения идентификаторов книг:
|
MySQL |
|
Решение 4.1.2.b (проверка работоспособности) |
||||
|
1 |
UPDATE |
`m2m_books_genres` |
||||
|
2 |
SET |
`g_id` = |
5 |
|
|
|
|
3 |
WHERE |
`b_id` = |
3 |
|
|
|
|
4 |
|
AND |
`g_id` = |
4; |
|
|
|
5 |
|
|
|
|
|
|
|
6 |
UPDATE |
`m2m_books_genres` |
||||
|
7 |
SET |
`g_id` = |
5 |
|
|
|
|
8 |
WHERE |
`b_id` = |
4 |
|
|
|
|
9 |
|
AND |
`g_id` = |
4; |
|
|
|
|
|
|
|
|
|
|
|
g_id |
|
|
g_name |
|
g_books |
|
|
1 |
Поэзия |
|
2 |
|
||
|
2 |
Программирование |
3 |
|
|||
|
3 |
Психология |
|
1 |
|
||
|
4 |
Наука |
|
0 |
|
||
|
5 |
Классика |
|
6 |
|
||
|
6 |
Фантастика |
|
1 |
|
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 307/545
Пример 32: обеспечение консистентности данных
Изменим в этих связях значения идентификаторов жанров, и идентификаторов книг одновременно:
|
MySQL |
|
Решение 4.1.2.b (проверка работоспособности) |
|||
|
1 |
|
UPDATE |
`m2m_books_genres` |
||
|
2 |
|
SET |
|
`b_id` = 1, |
|
|
3 |
|
|
|
|
`g_id` = 4 |
|
4 |
|
WHERE |
`b_id` = 3 |
||
|
5 |
|
|
|
AND |
`g_id` = 5; |
|
6 |
|
|
|
|
|
|
7 |
|
UPDATE |
`m2m_books_genres` |
||
|
8 |
|
SET |
|
`b_id` = 2, |
|
|
|
|
|
|
|
|
9`g_id` = 4
10WHERE `b_id` = 4
11AND `g_id` = 5;
g_id |
g_name |
g_books |
1 |
Поэзия |
2 |
2 |
Программирование |
3 |
3 |
Психология |
1 |
4 |
Наука |
2 |
5 |
Классика |
4 |
6 |
Фантастика |
1 |
Удалим эти созданные для проверки работоспособности решения связи:
MySQL Решение 4.1.2.b (проверка работоспособности)
|
1 |
DELETE |
FROM `m2m_books_genres` |
||
|
2 |
WHERE |
`b_id` = 1 |
|
|
|
3 |
AND |
`g_id` = 4; |
|
|
|
4 |
|
|
|
|
|
5 |
DELETE |
FROM `m2m_books_genres` |
||
|
6 |
WHERE |
`b_id` = 2 |
|
|
|
7 |
AND |
`g_id` = 4; |
|
|
|
|
|
|
|
|
|
g_id |
|
g_name |
g_books |
|
|
1 |
Поэзия |
2 |
|
|
|
2 |
Программирование |
3 |
|
|
|
3 |
Психология |
1 |
|
|
|
4 |
Наука |
0 |
|
|
|
5 |
Классика |
4 |
|
|
|
6 |
Фантастика |
1 |
|
Удалим книги с идентификаторами 1 и 2 (обе эти книги одновременно относятся к жанрам «Поэзия» и «Классика»):
MySQL Решение 4.1.2.b (проверка работоспособности)
1DELETE FROM `books`
2WHERE `b_id` IN (1, 2)
g_id |
g_name |
g_books |
1 |
Поэзия |
0 |
2 |
Программирование |
3 |
3 |
Психология |
1 |
4 |
Наука |
0 |
5 |
Классика |
2 |
6 |
Фантастика |
1 |
Итак, решение для MySQL завершено и проверено.
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 308/545
Пример 32: обеспечение консистентности данных
Переходим к решению для MS SQL Server. Модифицируем таблицу и проинициализируем данные.
MS SQL Решение 4.1.2.b (модификация таблицы и инициализация данных)
1-- Модификация таблицы:
2ALTER TABLE [genres]
3ADD [g_books] INT NOT NULL DEFAULT 0;
4
5-- Инициализация данных:
6UPDATE [genres]
7 |
|
SET |
[g_books] = [g_has_books] |
|
8 |
|
FROM |
[genres] |
|
9 |
|
|
JOIN (SELECT |
[g_id], |
10 |
|
|
|
COUNT([b_id]) AS [g_has_books] |
11 |
|
|
FROM |
[m2m_books_genres] |
12 |
|
|
GROUP |
BY [g_id]) AS [prepared_data] |
13ON [genres].[g_id] = [prepared_data].[g_id];
ВMS SQL Server триггеры активируются каскадными операциями, потому здесь будет достаточно создать триггеры только на таблице m2m_books_genres.
INSERT- и DELETE-триггеры достаточно просты: каждый из них подсчитывает
количество книг, добавленных к жанру или убранных у жанра, и изменяет счётчик книг у соответствующего жанра на полученное значение.
MS SQL Решение 4.1.2.b (триггеры для таблицы m2m_books_genres)
1-- Реакция на добавление связи между книгами и жанрами:
2CREATE TRIGGER [g_has_books_on_m2m_b_g_ins]
3ON [m2m_books_genres]
4AFTER INSERT
5AS
6UPDATE [genres]
7 |
|
SET |
[g_books] = [g_books] + |
[g_new_books] |
|
8 |
|
FROM |
[genres] |
|
|
9 |
|
|
JOIN (SELECT |
[g_id], |
|
10 |
|
|
|
COUNT([b_id]) AS [g_new_books] |
|
11 |
|
|
FROM |
[inserted] |
|
12 |
|
|
GROUP |
BY [g_id]) |
AS [prepared_data] |
13ON [genres].[g_id] = [prepared_data].[g_id];
14GO
15
16-- Реакция на обновление связи между книгами и жанрами:
17CREATE TRIGGER [g_has_books_on_m2m_b_g_upd]
18ON [m2m_books_genres]
19AFTER UPDATE
20AS
21UPDATE [genres]
22 |
|
SET |
[g_books] = [g_books] + [delta] |
||
23 |
|
FROM |
[genres] |
|
|
24 |
|
|
JOIN (SELECT [g_id], |
|
|
25 |
|
|
|
SUM([delta]) AS [delta] |
|
26 |
|
|
FROM |
(SELECT |
[g_id], |
27 |
|
|
|
|
-COUNT([b_id]) AS [delta] |
28 |
|
|
|
FROM |
[deleted] |
29 |
|
|
|
GROUP |
BY [g_id] |
30 |
|
|
|
UNION |
|
31 |
|
|
|
SELECT |
[g_id], |
32 |
|
|
|
|
COUNT([b_id]) AS [delta] |
33 |
|
|
|
FROM |
[inserted] |
34 |
|
|
|
GROUP |
BY [g_id]) AS [raw_deltas] |
35 |
|
|
GROUP |
BY [g_id]) AS [ready_delta] |
36ON [genres].[g_id] = [ready_delta].[g_id];
37GO
Работа с MySQL, MS SQL Server и Oracle в примерах © EPAM Systems, RD Dep, 2016–2018 Стр: 309/545