27.4.1 Синтаксис триггеров и примеры
Для создания или удаления триггера используйте оператор CREATE TRIGGER или DROP TRIGGER, описанные в разделе 15.1.23, «Оператор CREATE TRIGGER» и разделе 15.1.36, «Оператор DROP TRIGGER».
Вот простой пример, который связывает триггер с таблицей для активации при операциях INSERT. Триггер работает как сумматор, суммируя значения, вставленные в один из столбцов таблицы.
mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
Query OK, 0 rows affected (0.03 sec)
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
FOR EACH ROW SET @sum = @sum + NEW.amount;
Query OK, 0 rows affected (0.01 sec)
Оператор CREATE TRIGGER создает триггер с именем ins_sum, связанный с таблицей account. Он также включает предложения, определяющие время действия триггера, событие срабатывания и действия при активации триггера:
Ключевое слово
BEFOREуказывает время действия триггера. В данном случае триггер активируется перед вставкой каждой строки в таблицу. Другое допустимое ключевое слово здесь —AFTER.Ключевое слово
INSERTуказывает событие срабатывания триггера; то есть тип операции, которая активирует триггер. В примере активация триггера происходит при операцияхINSERT. Вы также можете создать триггеры для операцийDELETEиUPDATE.Предложение после
FOR EACH ROWопределяет тело триггера; то есть оператор, который выполняется каждый раз при активации триггера, что происходит один раз для каждой строки, затронутой событием срабатывания. В примере тело триггера представляет собой просто операторSET, который накапливает в переменной пользователя значения, вставленные в столбецamount. Оператор ссылается на столбец как наNEW.amount, что означает “значение столбцаamount, которое должно быть вставлено в новую строку”.
Для использования триггера установите переменную-сумматор в ноль, выполните оператор INSERT, а затем проверьте значение переменной:
mysql> SET @sum = 0;
mysql> INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
mysql> SELECT @sum AS 'Total amount inserted';
+-----------------------+
| Total amount inserted |
+-----------------------+
| 1852.48 |
+-----------------------+
В этом случае значение @sum после выполнения оператора INSERT будет 14.98 + 1937.50 - 100, или 1852.48.
Для удаления триггера используйте оператор DROP
TRIGGER. Вы должны указать имя схемы, если триггер не находится в схеме по умолчанию:
mysql> DROP TRIGGER test.ins_sum;
Если вы удаляете таблицу, любые триггеры для этой таблицы также удаляются.
Имена триггеров существуют в пространстве имен схемы, что означает, что все триггеры должны иметь уникальные имена в рамках одной схемы. Триггеры в разных схемах могут иметь одинаковые имена.
Можно определить несколько триггеров для одной таблицы с одинаковым событием срабатывания и временем действия. Например, вы можете иметь два BEFORE UPDATE триггера для одной таблицы. По умолчанию триггеры с одинаковым событием срабатывания и временем действия активируются в порядке их создания. Для изменения порядка активации укажите предложение после FOR EACH ROW, которое указывает на FOLLOWS или PRECEDES и имя существующего триггера, имеющего то же событие срабатывания и время действия. С помощью FOLLOWS новый триггер активируется после существующего триггера. С помощью PRECEDES новый триггер активируется перед существующим триггером.
Например, следующее определение триггера определяет другой BEFORE INSERT триггер для таблицы account:
mysql> CREATE TRIGGER ins_transaction BEFORE INSERT ON account
FOR EACH ROW PRECEDES ins_sum
SET
@deposits = @deposits + IF(NEW.amount>0,NEW.amount,0),
@withdrawals = @withdrawals + IF(NEW.amount<0,-NEW.amount,0);
Query OK, 0 rows affected (0.01 sec)
Этот триггер, ins_transaction, аналогичен ins_sum, но суммирует депозиты и снятия отдельно. Он имеет предложение PRECEDES, которое заставляет его активироваться до ins_sum; без этого предложения он бы активировался после ins_sum, потому что он создан после ins_sum.
Внутри тела триггера ключевые слова OLD и NEW позволяют получить доступ к столбцам в строках, затронутых триггером. OLD и NEW являются расширениями MySQL для триггеров; они не чувствительны к регистру.
В триггере INSERT можно использовать только NEW.; старой строки нет. В триггере col_nameDELETE можно использовать только OLD.; новой строки нет. В триггере col_nameUPDATE можно использовать OLD. для ссылки на столбцы строки до обновления и col_nameNEW. для ссылки на столбцы строки после обновления. col_name
Столбец с именем OLD доступен только для чтения. Вы можете ссылаться на него (если у вас есть привилегия SELECT), но не можете его изменять. Вы можете ссылаться на столбец с именем NEW, если у вас есть привилегия SELECT для него. В триггере BEFORE вы также можете изменить его значение с помощью SET NEW., если у вас есть привилегия col_name =
valueUPDATE для него. Это означает, что вы можете использовать триггер для изменения значений, которые будут вставлены в новую строку или использованы для обновления строки. (Такое предложение SET не имеет эффекта в триггере AFTER, потому что изменение строки уже произошло).
В триггере BEFORE значение NEW для столбца AUTO_INCREMENT равно 0, а не номер последовательности, который генерируется автоматически при фактической вставке новой строки.
Используя конструкцию BEGIN ...
END, вы можете определить триггер, который выполняет несколько операторов. Внутри блока BEGIN вы также можете использовать другой синтаксис, разрешенный в хранимых процедурах, таких как условные операторы и циклы. Однако, так же как и для хранимых процедур, если вы используете программу mysql для определения триггера, который выполняет несколько операторов, необходимо переопределить разделитель операторов mysql, чтобы вы могли использовать разделитель операторов ; внутри определения триггера. Следующий пример иллюстрирует эти моменты. Он определяет триггер UPDATE, который проверяет новое значение для обновления каждой строки и изменяет значение на значение в диапазоне от 0 до 100. Это должен быть триггер BEFORE, так как значение должно быть проверено до его использования для обновления строки:
mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
FOR EACH ROW
BEGIN
IF NEW.amount < 0 THEN
SET NEW.amount = 0;
ELSEIF NEW.amount > 100 THEN
SET NEW.amount = 100;
END IF;
END;//
mysql> delimiter ;
Иногда проще определить отдельную хранимую процедуру, а затем вызвать ее из триггера с помощью простого оператора CALL. Это также выгодно, если вы хотите выполнить один и тот же код из нескольких триггеров.
Существуют ограничения на то, что может появляться в операторах, выполняемых триггером при активации:
Триггер не может использовать оператор
CALLдля вызова хранимых процедур, которые возвращают данные клиенту или используют динамический SQL. (Хранимые процедуры могут возвращать данные триггеру через параметрыOUTилиINOUT).Триггер не может использовать операторы, которые явно или неявно начинают или заканчивают транзакцию, такие как
START TRANSACTION,COMMITилиROLLBACK. (ROLLBACK to SAVEPOINTразрешено, потому что оно не завершает транзакцию).
См. также раздел 27.9, «Ограничения для хранимых программ».
MySQL обрабатывает ошибки при выполнении триггера следующим образом:
Если триггер
BEFOREтерпит неудачу, операция над соответствующей строкой не выполняется.Триггер
BEFOREактивируется по попытке вставить или изменить строку, независимо от того, удастся эта попытка или нет.Триггер
AFTERвыполняется только в том случае, если всеBEFOREтриггеры и операция над строкой выполняется успешно.Ошибка во время работы триггера
BEFOREилиAFTERприводит к ошибке всего оператора, вызвавшего вызов триггера.Для таблиц с транзакциями неудача оператора должна привести к откату всех изменений, выполненных этим оператором. Неудача триггера приводит к неудаче оператора, следовательно, неудача триггера также приводит к откату. Для нетранзакционных таблиц такого отката сделать нельзя, поэтому, хотя оператор и завершается с ошибкой, любые изменения, выполненные до точки ошибки, остаются в силе.
Триггеры могут содержать прямые ссылки на таблицы по имени, например, триггер с именем testref, показанный в этом примере:
CREATE TABLE test1(a1 INT);
CREATE TABLE test2(a2 INT);
CREATE TABLE test3(a3 INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE test4(
a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
b4 INT DEFAULT 0
);
delimiter |
CREATE TRIGGER testref BEFORE INSERT ON test1
FOR EACH ROW
BEGIN
INSERT INTO test2 SET a2 = NEW.a1;
DELETE FROM test3 WHERE a3 = NEW.a1;
UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
END;
|
delimiter ;
INSERT INTO test3 (a3) VALUES
(NULL), (NULL), (NULL), (NULL), (NULL),
(NULL), (NULL), (NULL), (NULL), (NULL);
INSERT INTO test4 (a4) VALUES
(0), (0), (0), (0), (0), (0), (0), (0), (0), (0);
Предположим, что вы вставляете следующие значения в таблицу test1, как показано здесь:
mysql> INSERT INTO test1 VALUES
(1), (3), (1), (7), (1), (8), (4), (4);
Query OK, 8 rows affected (0.01 sec)
Records: 8 Duplicates: 0 Warnings: 0
В результате четыре таблицы содержат следующие данные:
mysql> SELECT * FROM test1;
+------+
| a1 |
+------+
| 1 |
| 3 |
| 1 |
| 7 |
| 1 |
| 8 |
| 4 |
| 4 |
+------+
8 rows in set (0.00 sec)
mysql> SELECT * FROM test2;
+------+
| a2 |
+------+
| 1 |
| 3 |
| 1 |
| 7 |
| 1 |
| 8 |
| 4 |
| 4 |
+------+
8 rows in set (0.00 sec)
mysql> SELECT * FROM test3;
+----+
| a3 |
+----+
| 2 |
| 5 |
| 6 |
| 9 |
| 10 |
+----+
5 rows in set (0.00 sec)
mysql> SELECT * FROM test4;
+----+------+
| a4 | b4 |
+----+------+
| 1 | 3 |
| 2 | 0 |
| 3 | 1 |
| 4 | 2 |
| 5 | 0 |
| 6 | 0 |
| 7 | 1 |
| 8 | 1 |
| 9 | 0 |
| 10 | 0 |
+----+------+
10 rows in set (0.00 sec)
© 2025 Oracle
Licensed under the GPLv2 License.