Евгений Колесников před 3 roky
rodič
revize
0912df56da
2 změnil soubory, kde provedl 120 přidání a 0 odebrání
  1. 118 0
      articles/sql_trigger.md
  2. 2 0
      readme.md

+ 118 - 0
articles/sql_trigger.md

@@ -0,0 +1,118 @@
+# Хранимые процедуры. Триггеры.
+
+## Хранимые процедуры
+
+**Хранимая процедура** - это способ инкапсуляции повторяющихся действий. В хранимых процедурах можно объявлять переменные, управлять потоками данных, а также применять другие техники программирования.
+
+**За**
+
+- Разделение логики с другими приложениями. Хранимые процедуры инкапсулируют функциональность; это обеспечивает связность доступа к данным и управления ими между различными приложениями.
+- Изоляция пользователей от таблиц базы данных. Это позволяет давать доступ к хранимым процедурам, но не к самим данным таблиц.
+- Обеспечивает механизм защиты. В соответствии с предыдущим пунктом, если вы можете получить доступ к данным только через хранимые процедуры, никто другой не сможет стереть ваши данные через команду SQL DELETE.
+- Улучшение выполнения как следствие сокращения сетевого трафика. С помощью хранимых процедур множество запросов могут быть объединены.
+
+**Против**
+
+- Повышение нагрузки на сервер баз данных в связи с тем, что большая часть работы выполняется на серверной части, а меньшая - на клиентской.
+- Придется много чего подучить. Вам понадобится выучить синтаксис MySQL выражений для написания своих хранимых процедур.
+- Вы дублируете логику своего приложения в двух местах: серверный код и код для хранимых процедур, тем самым усложняя процесс манипулирования данными.
+- Миграция с одной СУБД на другую (DB2, SQL Server и др.) может привести к проблемам.
+
+**Ограничитель (Delimiter)** - это символ или строка символов, который используется для указания клиенту MySQL, что вы завершили написание выражения SQL. В обычных запросах в качестве ограничителя используется символ точки с запятой. Тем не менее, могут возникнуть проблемы, так как в хранимой процедуре может быть несколько выражений, каждое из которых должно заканчиваться точкой с запятой. В этом уроке я использую символ `|` в качестве ограничителя.
+
+## Триггеры
+
+<!-- https://www.digitalocean.com/community/tutorials/how-to-manage-and-use-mysql-database-triggers-on-ubuntu-18-04-ru -->
+
+**Триггер** — это хранимая откомпилированная SQL-процедура, которая не вызывается непосредственно, а исполняется при наступлении определенного события внутри базы данных (вставки, удаления, обновления записей).
+
+Хранимые процедуры запускают во всех средах, и нет необходимости перестроения логики. С того момента как вы создали хранимую процедуру, не важно какое приложение вы используете для вызова процедуры. Также не важно на каком языке вы программируете, логика процедуры содержится на сервере БД.
+
+Также хранимые процедуры могут сократить сетевой трафик. Сложные, повторяющиеся задачи можно обрабатывать с помощью процедур на сервере Баз данных, без необходимости отсылки промежуточных результатов приложению.
+
+Триггеры применяются для обеспечения целостности данных и реализации сложной бизнес-логики. Триггер запускается сервером автоматически при попытке изменения данных в таблице, с которой он связан. Все производимые им модификации данных рассматриваются как выполняемые в транзакции, в которой выполнено действие, вызвавшее срабатывание триггера. Соответственно, в случае обнаружения ошибки или нарушения целостности данных может произойти откат этой транзакции.
+
+Общий вид синтаксиса для создания тригера:
+
+```sql
+CREATE TRIGGER 
+    trigger_name trigger_time trigger_event
+    ON tbl_name FOR EACH ROW trigger_body
+```
+
+где:
+
+- *trigger_name* - название триггера (уникальное в пределах БД);
+- *trigger_time* - время срабатывания триггера. **BEFORE** — перед событием. **AFTER** — после события;
+- *trigger_event* - событие:
+    * *insert* — событие возбуждается операторами *insert*, *data load*, *replace*;
+    * *update* — событие возбуждается оператором *update*;
+    * *delete* — событие возбуждается операторами *delete*, *replace*. Операторы *DROPTABLE* и *TRUNCATE* не активируют выполнение триггера;
+
+    Важно понимать, что *trigger_event* не представляет литеральный тип инструкции SQL, которая активизирует триггер. Например, триггер INSERT активизируется не только инструкцией INSERT, но и LOAD DATA, потому что обе инструкции вставляют строки в таблицу.
+
+- *tbl_name* — название таблицы;
+- *trigger_body* — выражение, которое выполняется при активации триггера. Если Вы хотите выполнять много инструкций, используйте операторную конструкцию `BEGIN ... END`. Это также дает возможность Вам использовать те же самые инструкции, которые являются допустимыми внутри сохраненных подпрограмм.
+
+Не может быть двух триггеров для данной таблицы, которые имеют те же самые время действия и событие. Например, Вы не можете иметь два триггера BEFORE UPDATE для таблицы. Но Вы можете иметь BEFORE UPDATE и BEFORE INSERT или BEFORE UPDATE и AFTER UPDATE.
+
+Триггеры могут быть привязаны не к таблице, а к представлению (VIEW). В этом случае с их помощью реализуется механизм "обновляемого представления".
+
+Например: создадим две таблицы **test** и **log**, напишем триггер, который после добавления записи в таблицу **test** будет вести лог этого события:
+
+```sql
+-- таблица, за которой мы будем следить
+CREATE TABLE `test` (
+    `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+    `content` TEXT NOT NULL
+);
+
+-- лог
+CREATE TABLE `log` (
+    `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+    `msg` VARCHAR( 255 ) NOT NULL,
+    `time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    `row_id` INT( 11 ) NOT NULL
+);
+
+-- триггер
+DELIMITER |
+CREATE TRIGGER `update_test` AFTER INSERT ON `test`
+FOR EACH ROW BEGIN
+   INSERT INTO log Set msg = 'insert', row_id = NEW.id;
+END;
+|
+```
+
+Здесь оператор DELIMITER служит для определения литерала начала/окончания процедуры и может состоять более, чем из одного символа (необходимо выбирать разделитель, который не будет использоваться в процедуре).
+
+На столбцы таблицы, к которой привязан триггер можно ссылаться с помощью псевдонимов **OLD** и **NEW**. `OLD.col_name` указывает на столбец с именем *col_name* **до** изменения или удаления данных. `NEW.col_name` относится к колонке новой строки после вставки или существующей - сразу после её обновления.
+
+Триггеры имеют несколько важных особенностей использования:
+
+- триггеры могут создаваться только пользователем с привилегией SUPER;
+- при использовании запроса, затрагивающего N - записей, триггер будет запускаться N - раз;
+- после удаления таблицы, СУБД MySQL автоматически удаляет привязанные к ней триггеры.
+
+```sql
+create trigger
+sale_item
+before insert
+on sales
+for each row
+ 	update warehouse set quantity=quantity - NEW.quantity where id=NEW.item_id; 
+```
+
+```sql
+delimiter $$
+CREATE trigger 
+update_warehouse
+before update 
+on warehouse 
+for EACH row begin
+	if NEW.quantity<0 THEN 
+		SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'На складе недостаточно товара';
+	END if;
+end;
+$$
+```

+ 2 - 0
readme.md

@@ -111,6 +111,8 @@ http://sergeyteplyakov.blogspot.com/2014/01/microsoft-fakes-state-verification.h
 
 6. [Создание базы данных. Импорт данных.](./articles/sql_import.md)
 
+7. [Хранимые процедуры. Триггеры.](./articles/sql_trigger.md)
+
 ### Контрольные вопросы
 
 * Что такое **домен**?