Trigger error message mysql

If I have a trigger before the update on a table, how can I throw an error that prevents the update on that table?

If I have a trigger before the update on a table, how can I throw an error that prevents the update on that table?

JKD's user avatar

JKD

1,2391 gold badge5 silver badges24 bronze badges

asked Aug 1, 2008 at 12:12

Matt MacLean's user avatar

Matt MacLeanMatt MacLean

19.2k7 gold badges49 silver badges53 bronze badges

0

As of MySQL 5.5, you can use the SIGNAL syntax to throw an exception:

signal sqlstate '45000' set message_text = 'My Error Message';

State 45000 is a generic state representing «unhandled user-defined exception».


Here is a more complete example of the approach:

delimiter //
use test//
create table trigger_test
(
    id int not null
)//
drop trigger if exists trg_trigger_test_ins //
create trigger trg_trigger_test_ins before insert on trigger_test
for each row
begin
    declare msg varchar(128);
    if new.id < 0 then
        set msg = concat('MyTriggerError: Trying to insert a negative value in trigger_test: ', cast(new.id as char));
        signal sqlstate '45000' set message_text = msg;
    end if;
end
//

delimiter ;
-- run the following as seperate statements:
insert into trigger_test values (1), (-1), (2); -- everything fails as one row is bad
select * from trigger_test;
insert into trigger_test values (1); -- succeeds as expected
insert into trigger_test values (-1); -- fails as expected
select * from trigger_test;

Drew's user avatar

Drew

24.7k10 gold badges43 silver badges78 bronze badges

answered Aug 25, 2011 at 11:14

RuiDC's user avatar

Here is one hack that may work. It isn’t clean, but it looks like it might work:

Essentially, you just try to update a column that doesn’t exist.

Laurel's user avatar

Laurel

5,90314 gold badges30 silver badges56 bronze badges

answered Aug 1, 2008 at 13:02

Justin's user avatar

JustinJustin

2,9045 gold badges41 silver badges65 bronze badges

1

Unfortunately, the answer provided by @RuiDC does not work in MySQL versions prior to 5.5 because there is no implementation of SIGNAL for stored procedures.

The solution I’ve found is to simulate a signal throwing a table_name doesn't exist error, pushing a customized error message into the table_name.

The hack could be implemented using triggers or using a stored procedure. I describe both options below following the example used by @RuiDC.

Using triggers

DELIMITER $$
-- before inserting new id
DROP TRIGGER IF EXISTS before_insert_id$$
CREATE TRIGGER before_insert_id
    BEFORE INSERT ON test FOR EACH ROW
    BEGIN
        -- condition to check
        IF NEW.id < 0 THEN
            -- hack to solve absence of SIGNAL/prepared statements in triggers
            UPDATE `Error: invalid_id_test` SET x=1;
        END IF;
    END$$

DELIMITER ;

Using a stored procedure

Stored procedures allows you to use dynamic sql, which makes possible the encapsulation of the error generation functionality in one procedure. The counterpoint is that we should control the applications insert/update methods, so they use only our stored procedure (not granting direct privileges to INSERT/UPDATE).

DELIMITER $$
-- my_signal procedure
CREATE PROCEDURE `my_signal`(in_errortext VARCHAR(255))
BEGIN
    SET @sql=CONCAT('UPDATE `', in_errortext, '` SET x=1');
    PREPARE my_signal_stmt FROM @sql;
    EXECUTE my_signal_stmt;
    DEALLOCATE PREPARE my_signal_stmt;
END$$

CREATE PROCEDURE insert_test(p_id INT)
BEGIN
    IF NEW.id < 0 THEN
         CALL my_signal('Error: invalid_id_test; Id must be a positive integer');
    ELSE
        INSERT INTO test (id) VALUES (p_id);
    END IF;
END$$
DELIMITER ;

answered Jan 28, 2012 at 15:46

el.atomo's user avatar

el.atomoel.atomo

5,0203 gold badges28 silver badges28 bronze badges

2

The following procedure is (on mysql5) a way to throw custom errors , and log them at the same time:

create table mysql_error_generator(error_field varchar(64) unique) engine INNODB;
DELIMITER $$
CREATE PROCEDURE throwCustomError(IN errorText VARCHAR(44))
BEGIN
    DECLARE errorWithDate varchar(64);
    select concat("[",DATE_FORMAT(now(),"%Y%m%d %T"),"] ", errorText) into errorWithDate;
    INSERT IGNORE INTO mysql_error_generator(error_field) VALUES (errorWithDate);
    INSERT INTO mysql_error_generator(error_field) VALUES (errorWithDate);
END;
$$
DELIMITER ;


call throwCustomError("Custom error message with log support.");

answered Nov 8, 2012 at 16:15

Marinos An's user avatar

Marinos AnMarinos An

8,8115 gold badges54 silver badges92 bronze badges

CREATE TRIGGER sample_trigger_msg 
    BEFORE INSERT
FOR EACH ROW
    BEGIN
IF(NEW.important_value) < (1*2) THEN
    DECLARE dummy INT;
    SELECT 
           Enter your Message Here!!!
 INTO dummy 
        FROM mytable
      WHERE mytable.id=new.id
END IF;
END;

answered Aug 12, 2016 at 18:08

BHUVANESH MOHANKUMAR's user avatar

1

Another (hack) method (if you are not on 5.5+ for some reason) that you can use:

If you have a required field, then within a trigger set the required field to an invalid value such as NULL. This will work for both INSERT and UPDATE. Do note that if NULL is a valid value for the required field (for some crazy reason) then this approach will not work.

BEGIN
    -- Force one of the following to be assigned otherwise set required field to null which will throw an error
    IF (NEW.`nullable_field_1` IS NULL AND NEW.`nullable_field_2` IS NULL) THEN
        SET NEW.`required_id_field`=NULL;
    END IF;
END

If you are on 5.5+ then you can use the signal state as described in other answers:

BEGIN
    -- Force one of the following to be assigned otherwise use signal sqlstate to throw a unique error
    IF (NEW.`nullable_field_1` IS NULL AND NEW.`nullable_field_2` IS NULL) THEN
        SIGNAL SQLSTATE '45000' set message_text='A unique identifier for nullable_field_1 OR nullable_field_2 is required!';
    END IF;
END

answered Apr 9, 2016 at 23:11

PhotonFalcon's user avatar

DELIMITER @@
DROP TRIGGER IF EXISTS trigger_name @@
CREATE TRIGGER trigger_name 
BEFORE UPDATE ON table_name
FOR EACH ROW
BEGIN

  --the condition of error is: 
  --if NEW update value of the attribute age = 1 and OLD value was 0
  --key word OLD and NEW let you distinguish between the old and new value of an attribute

   IF (NEW.state = 1 AND OLD.state = 0) THEN
       signal sqlstate '-20000' set message_text = 'hey it's an error!';     
   END IF;

END @@ 
DELIMITER ;

answered Jun 1, 2020 at 15:48

Bashir's user avatar

BashirBashir

2,0475 gold badges18 silver badges43 bronze badges

3 марта, 2020 12:36 пп
1 293 views
| Комментариев нет

mySQL, Ubuntu

Триггеры (trigger) в MySQL – это определяемые пользователем SQL-команды, которые автоматически вызываются во время операций INSERT, DELETE или UPDATE. Код триггера связан с таблицей и уничтожается после удаления таблицы. Пользователь может определить время действия триггера и указать, когда его нужно активировать – до или после определенного события базы данных.

Триггеры имеют несколько преимуществ. Например, вы можете использовать их для генерации значения производного столбца во время выполнения INSERT. Еще один вариант использования триггера – обеспечение ссылочной целостности при сохранении записи в нескольких связанных таблицах. Также к преимуществам триггеров относятся регистрация действий пользователя для аудита таблиц и оперативное копирование данных в разных схемах БД (для обеспечения избыточности и предотвращения единой точки отказа).

Вы также можете использовать триггеры, чтобы сохранить правила проверки на уровне базы данных. Это бывает необходимо при совместном использовании одного источника данных несколькими приложениями – так можно избежать нарушения бизнес-логики. Это значительно уменьшает количество обращений к серверу БД, что, следовательно, улучшает время отклика приложения.

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

Требования

  • Сервер Ubuntu 18.04, настроенный согласно этому мануалу.
  • Сервер MySQL, настроить который вам поможет этот мануал.
  • Учетные данные пользователя root MySQL.

1: Создание базы данных

Для начала давайте создадим тестовую БД с несколькими таблицами. На ее примере мы будем учиться работать с триггерами.

Читайте также: Запросы в MySQL

Войдите на сервер MySQL как root:

mysql -u root -p

При появлении запроса введите свой root пароль MySQL и нажмите клавишу Enter, чтобы продолжить. Когда вы увидите префикс mysql> в командной строке, выполните следующую команду, чтобы создать БД test_db:

Create database test_db;
Query OK, 1 row affected (0.00 sec)

Затем перейдите в test_db с помощью этой команды:

Use test_db;
Database changed

Теперь создадим таблицу customers. В этой таблице будут храниться записи клиентов, в том числе customer_id, customer_name и level. У нас будет две категории клиентов: BASIC и VIP.

Create table customers(customer_id BIGINT PRIMARY KEY, customer_name VARCHAR(50), level VARCHAR(50) ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

Теперь добавьте в таблицу несколько записей. Для этого выполните следующие команды одну за другой:

Insert into customers (customer_id, customer_name, level )values('1','JOHN DOE','BASIC');
Insert into customers (customer_id, customer_name, level )values('2','MARY ROE','BASIC');
Insert into customers (customer_id, customer_name, level )values('3','JOHN DOE','VIP');

После выполнения каждой команды INSERT вы увидите следующий вывод:

Query OK, 1 row affected (0.01 sec)

Чтобы убедиться, что тестовые записи были успешно вставлены в таблицу, выполните команду SELECT:

Select * from customers;
+-------------+---------------+-------+
| customer_id | customer_name | level |
+-------------+---------------+-------+
|           1 | JOHN DOE      | BASIC |
|           2 | MARY ROE      | BASIC |
|           3 | JOHN DOE      | VIP   |
+-------------+---------------+-------+
3 rows in set (0.00 sec)

Затем мы создадим еще одну таблицу, customer_status, для хранения соответствующей информации об учетной записи клиентов. Таблица будет иметь поля customer_id и status_notes.

Запустите следующую команду:

Create table customer_status(customer_id BIGINT PRIMARY KEY, status_notes VARCHAR(50)) ENGINE=INNODB;

Затем мы создадим таблицу sales. В этой таблице будут храниться данные о продажах, связанные с другими таблицами через столбец customer_id:

Create table sales(sales_id BIGINT PRIMARY KEY, customer_id BIGINT, sales_amount DOUBLE ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

Данные в таблицу sales мы добавим во время тестирования триггеров. Сейчас создайте таблицу audit_log для регистрации обновлений, внесенных в таблицу sales после выполнения триггера AFTER UPDATE в разделе 5:

Create table audit_log(log_id BIGINT PRIMARY KEY AUTO_INCREMENT, sales_id BIGINT, previous_amount DOUBLE, new_amount DOUBLE, updated_by VARCHAR(50), updated_on DATETIME ) ENGINE=INNODB;
Query OK, 0 rows affected (0.02 sec)

Теперь у вас есть тестовая БД test_db и четыре таблицы. Давайте попробуем поработать с различными триггерами MySQL.

2: Создание триггера BEFORE INSERT

На этом этапе вы изучите синтаксис триггеров MySQL, а затем научитесь применять эту логику для создания триггера BEFORE INSERT, который проверяет поле sales_amount при вставке данных в таблицу sales.

Общий синтаксис для создания триггера MySQL выглядит так:

DELIMITER //
CREATE TRIGGER [TRIGGER_NAME]
[TRIGGER TIME] [TRIGGER EVENT]
ON [TABLE]
FOR EACH ROW
[TRIGGER BODY]//
DELIMITER ;

В состав триггера входят такие компоненты:

  • DELIMITER //: Разделитель MySQL по умолчанию – это точка с запятой (;). Его необходимо заменить чем-то другим, чтобы MySQL рассматривал все строки как одну команду, пока не достигнет пользовательского разделителя. В этом примере мы выбрали в качестве пользовательского разделителя два слеша (//). Стандартный разделитель (;) стоит в конце выражения.
  • [TRIGGER_NAME]: триггер должен иметь имя, и именно здесь вы можете его указать.
  • [TRIGGER TIME]: триггер можно вызывать в разные моменты времени. MySQL позволяет вам определить, когда запускать триггер – до или после операции с БД.
  • [TRIGGER EVENT]: триггеры вызываются только операциями INSERT, UPDATE и DELETE. Здесь вы можете использовать любое из этих значений в зависимости от того, чего вы хотите достичь.
  • [TABLE]: каждый триггер, который вы создаете в своей базе данных MySQL, должен быть связан с таблицей. Здесь нужно ее указать.
  • FOR EACH ROW: этот оператор позволяет MySQL выполнять код триггера для каждой строки в таблице.
  • [TRIGGER BODY]: код, который выполняется при вызове триггера, называется телом триггера. Это может быть один SQL оператор или несколько команд. Обратите внимание, если в теле триггера вы выполняете несколько SQL операторов, вы должны заключить их в блок BEGIN … END.

Примечание: При создании тела триггера вы можете использовать ключевые слова OLD и NEW для доступа к старым и новым значениям столбца, введенным во время операций INSERT, UPDATE и DELETE. В триггере DELETE можно использовать только ключевое слово OLD (подробнее об этом – в разделе 4).

Теперь вы можете создать свой первый триггер BEFORE INSERT. Этот триггер будет связан с таблицей sales, он будет вызываться перед вставкой записи для проверки sales_amount. Функция триггера состоит в том, чтобы проверить, является ли значение sales_amount, добавляемое в таблицу продаж, больше 10000, и выдать ошибку, если это оценивается как true.

Убедитесь, что вы вошли на сервер MySQL. Затем введите следующие команды MySQL одну за другой:

DELIMITER //
CREATE TRIGGER validate_sales_amount
BEFORE INSERT
ON sales
FOR EACH ROW
IF NEW.sales_amount>10000 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Sale has exceeded the allowed amount of 10000.';
END IF//
DELIMITER ;

Оператор IF … THEN … END IF позволяет оценить, находится ли сумма, указанная в операторе INSERT, в пределах вашего диапазона. Триггер может извлечь новое значение sales_amount, используя ключевое слово NEW.

Чтобы вызвать общее сообщение об ошибке, мы используем здесь следующие строки:

SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Sale has exceeded the allowed amount of 10000.';

Теперь вставьте запись sales_amount со значением 11000 в таблицу sales, чтобы проверить, остановит ли триггер операцию:

Insert into sales(sales_id, customer_id, sales_amount) values('1','1','11000');
ERROR 1644 (45000): Sale has exceeded the allowed amount of 10000.

Эта ошибка показывает, что код триггера работает должным образом.

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

Insert into  sales(sales_id, customer_id, sales_amount) values('1','1','7500');

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

Query OK, 1 row affected (0.01 sec)

Чтобы убедиться, что данные были вставлены, выполните следующую команду:

Select * from sales;

Вывод подтверждает, что данные находятся в таблице:

+----------+-------------+--------------+
| sales_id | customer_id | sales_amount |
+----------+-------------+--------------+
|        1 |           1 |         7500 |
+----------+-------------+--------------+
1 row in set (0.00 sec)

Итак, вы протестировали триггеры для проверки данных перед вставкой в БД.

Теперь давайте попробуем поработать с триггером AFTER INSERT, чтобы сохранить связанную информацию в разных таблицах.

3: Создание триггера AFTER INSERT

Триггеры AFTER INSERT выполняются после того как записи успешно вставлены в таблицу. Эта функция может использоваться для автоматического запуска других бизнес-логик. Например, в банковском приложении триггер AFTER INSERT может закрыть ссудный счет, когда клиент погасит ссуду. Триггер может отслеживать все платежи, вставленные в таблицу транзакций, и автоматически закрыть ссуду, когда остаток будет равен нулю.

На этом этапе мы будем работать с таблицей customer_status, используя триггер AFTER INSERT для ввода связанных записей о клиентах.

Чтобы создать триггер AFTER INSERT, введите следующие команды:

DELIMITER //
CREATE TRIGGER customer_status_records
AFTER INSERT
ON customers
FOR EACH ROW
Insert into customer_status(customer_id, status_notes) VALUES(NEW.customer_id, 'ACCOUNT OPENED SUCCESSFULLY')//
DELIMITER ;
Query OK, 0 rows affected (0.00 sec)

Эти команды говорят MySQL сохранить еще одну запись в таблицу customer_status, как только новая запись о клиенте будет добавлена ​​в таблицу customers.

Теперь вставьте новую запись в таблицу customers, чтобы убедиться, что триггер вызывается:

Insert into customers (customer_id, customer_name, level )values('4','DAVID DOE','VIP');
Query OK, 1 row affected (0.01 sec)

Поскольку запись была ​​успешно вставлена в таблицу customers, убедитесь, что новая запись о статусе была добавлена ​​в таблицу customer_status:

Select * from customer_status;
+-------------+-----------------------------+
| customer_id | status_notes                |
+-------------+-----------------------------+
|           4 | ACCOUNT OPENED SUCCESSFULLY |
+-------------+-----------------------------+
1 row in set (0.00 sec)

Выходные данные подтверждают, что триггер работает успешно.

Триггер AFTER INSERT полезен для мониторинга жизненного цикла клиента. В производственной среде учетные записи клиентов могут проходить различные этапы (например, открытие, приостановка и закрытие счета).

4: Создание триггера BEFORE UPDATE

Триггер BEFORE UPDATE похож на триггер BEFORE INSERT. Разница только в том, когда они вызываются. Вы можете использовать триггер BEFORE UPDATE, чтобы проверить бизнес-логику перед обновлением записи. Чтобы посмотреть, как он работает, используйте таблицу customers, в которую уже вставлены некоторые данные.

В базе данных есть два уровня клиентов. Для примера представим себе такую ситуацию: как только учетная запись клиента будет обновлена до уровня VIP, она не сможет быть понижена до уровня BASIC. Чтобы применить такое правило, мы создадим триггер BEFORE UPDATE, который будет выполняться перед оператором UPDATE. Если пользователь базы данных попытается понизить клиента до уровня BASIC с уровня VIP, будет сгенерировано пользовательское исключение.

Введите следующие команды SQL одну за другой, чтобы создать триггер BEFORE UPDATE:

DELIMITER //
CREATE TRIGGER validate_customer_level
BEFORE UPDATE
ON customers
FOR EACH ROW
IF OLD.level='VIP' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'A VIP customer can not be downgraded.';
END IF //
DELIMITER ;

Ключевое слово OLD позволяет зафиксировать уровень, предоставленный пользователем при выполнении команды UPDATE. Опять же, вы используете оператор IF … THEN … END IF, чтобы сообщить пользователю об ошибке.

Затем выполните следующую SQL команду, которая попытается понизить учетную запись клиента, связанную с customer_id 3:

Update customers set level='BASIC' where customer_id='3';

Вы увидите следующий вывод, предоставляющий SET MESSAGE_TEXT:

ERROR 1644 (45000): A VIP customer can not be downgraded.

Если вы выполните ту же команду для клиента уровня BASIC и попытаетесь повысить учетную запись до уровня VIP, команда выполнится успешно:

Update customers set level='VIP' where customer_id='1';
Rows matched: 1  Changed: 1  Warnings: 0

Теперь давайте посмотрим, как работает триггер AFTER UPDATE для ведения журнала аудита.

5: Создание триггера AFTER UPDATE

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

Давайте создадим триггер, который регистрирует активность обновления таблицы sales. Таблица audit_log будет содержать информацию о пользователях MySQL, обновляющих таблицу sales, дату обновления, а также новые и старые значения sales_amount.

Чтобы создать триггер, выполните следующие команды SQL:

DELIMITER //
CREATE TRIGGER log_sales_updates
AFTER UPDATE
ON sales
FOR EACH ROW
Insert into audit_log(sales_id, previous_amount, new_amount, updated_by, updated_on) VALUES (NEW.sales_id,OLD.sales_amount, NEW.sales_amount,(SELECT USER()), NOW() )//
DELIMITER ;

Вы вставляете новую запись в таблицу audit_log. Ключевое слово NEW позволяет получить значение sales_id и новое значение sales_amount. Ключевое слово OLD выдает предыдущие значения sales_amount, благодаря чему вы можете зарегистрировать обе суммы для аудита.

Команда SELECT USER() извлекает текущего пользователя, выполняющего операцию, а NOW () извлекает значение текущей даты и времени с сервера MySQL.

Если теперь пользователь попытается обновить значение какой-либо записи в таблице sales, триггер log_sales_updates вставит новую запись в таблицу audit_log.

Давайте создадим новую запись о продажах с у словным значением sales_id, равным 5, и попробуем обновить ее. Сначала вставьте запись о продажах:

Insert into sales(sales_id, customer_id, sales_amount) values('5', '2','8000');
Query OK, 1 row affected (0.00 sec)

Затем обновите эту запись:

Update sales set sales_amount='9000' where sales_id='5';

Вы получите такой вывод:

Rows matched: 1  Changed: 1  Warnings: 0

Теперь выполните следующую команду, чтобы проверить, смог ли триггер AFTER UPDATE зарегистрировать новую запись в таблице audit_log:

Select * from audit_log;

Триггер зарегистрировал обновление. Ваш вывод покажет предыдущий sales_amount и новую сумму, зарегистрированную пользователем, который обновил запись:

+--------+----------+-----------------+------------+----------------+---------------------+
| log_id | sales_id | previous_amount | new_amount | updated_by     | updated_on          |
+--------+----------+-----------------+------------+----------------+---------------------+
|      1 |        5 |            8000 |       9000 | root@localhost | 2019-11-07 09:28:36 |
+--------+----------+-----------------+------------+----------------+---------------------+
1 row in set (0.00 sec)

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

Далее мы рассмотрим триггер DELETE для обеспечения целостности ссылок на уровне базы данных.

6: Создание триггера BEFORE DELETE

Триггеры BEFORE DELETE вызываются до выполнения операции DELETE. Этот вид триггеров обычно используется для обеспечения ссылочной целостности в разных связанных таблицах. Например, каждая запись в таблице sales  связана с записью в таблице customers через столбец customer_id. Если пользователь базы данных удалил из таблицы customers запись, у которой есть связанная запись в таблице sales, у вас не будет возможности узнать, какой клиент был связан с этой записью.

Чтобы избежать подобных ситуаций и сделать логику более надежной, вы можете создать триггер BEFORE DELETE. Выполните следующие SQL команды одну за другой:

DELIMITER //
CREATE TRIGGER validate_related_records
BEFORE DELETE
ON customers
FOR EACH ROW
IF OLD.customer_id in (select customer_id from sales) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'The customer has a related sales record.';
END IF//
DELIMITER ;

Теперь попробуйте удалить клиента, у которого есть связанная запись в таблице sales:

Delete from customers where customer_id='2';

В результате вы получите следующий вывод:

ERROR 1644 (45000): The customer has a related sales record.

Триггер BEFORE DELETE может предотвратить случайное удаление связанной информации в базе данных.

Однако в некоторых ситуациях может потребоваться удалить из разных таблиц все записи, связанные с конкретной записью,. В этой ситуации вы бы использовали триггер AFTER DELETE, который мы и рассмотрим далее.

7: Создание триггера AFTER DELETE

Триггеры AFTER DELETE активируются, когда запись была успешно удалена. Примером использования триггера AFTER DELETE является такая ситуация: скидка, которую получает конкретный клиент, определяется количеством покупок, совершенных этим клиентом в течение определенного периода. Следовательно, если некоторые из записей клиента будут удалены из таблицы sales, скидка для этого клиента должна уменьшиться.

Еще один вариант использования триггера AFTER DELETE – удаление связанной информации из других таблиц после удаления записи из базовой таблицы. Например, вы можете установить триггер, который удалит запись о клиенте, если записи о продажах с соответствующим customer_id будут удалены из таблицы sales. Запустите следующую команду, чтобы создать такой триггер:

DELIMITER //
CREATE TRIGGER delete_related_info
AFTER DELETE
ON sales
FOR EACH ROW
Delete from customers where customer_id=OLD.customer_id;//
DELIMITER ;

Теперь запустите следующую команду, чтобы удалить все записи о продажах для клиента с customer_id 2.

Delete from sales where customer_id='2';
Query OK, 1 row affected (0.00 sec)

Проверьте, удалились ли записи для этого клиента из таблицы sales:

Select * from customers where customer_id='2';

Вы получите вывод Empty Set, поскольку запись клиента, связанная с customer_id 2, была удалена триггером:

Empty set (0.00 sec)

Вы научились работать с разными видами триггеров. Далее мы покажем, как удалить триггер из базы данных, если он вам больше не нужен.

8: Удаление триггеров

Как и любой другой объект базы данных, вы можете удалить триггеры с помощью команды DROP. Вот синтаксис для удаления триггера:

Drop trigger [TRIGGER NAME];

Например, чтобы удалить последний созданный триггер, AFTER DELETE, выполните следующую команду:

Drop trigger delete_related_info;
Query OK, 0 rows affected (0.00 sec)

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

Заключение

В этом мануале вы научились создавать, использовать и удалять триггеры MySQL. Проверка данных, применение бизнес-логики, ведение журнала аудита и обеспечение ссылочной целостности – основные варианты применения триггеров, с которыми вы столкнулись.

Читайте также:

  • Оптимизация работы MySQL с помощью кэша запросов в Ubuntu 18.04
  • Постраничный вывод данных на MySQL и PHP в Ubuntu 18.04
  • Доступ к логам ошибок MySQL

Tags: MySQL, Ubuntu 18.04

Introduction

MySQL triggers apply restrictions to tables when adding, updating, or removing table rows.

Columns in MySQL apply a slight amount of value limitations. For example, setting a column data type as tiny int and not null requires a small number value input. Still, more restrictions are needed to maintain the integrity of data.

This tutorial shows you how to use MySQL triggers and provides examples for each type of trigger.

How To Use MySQL Triggers

Prerequisites

  • A system running MySQL on a database server
  • MySQL user account with root privileges
  • Knowledge of basic MySQL commands (refer to our downloadable MySQL commands cheat sheet)

What is a Trigger in MySQL?

A trigger is a named MySQL object that activates when an event occurs in a table. Triggers are a particular type of stored procedure associated with a specific table.

Triggers allow access to values from the table for comparison purposes using NEW and OLD. The availability of the modifiers depends on the trigger event you use:

Trigger Event OLD NEW
INSERT No Yes
UPDATE Yes Yes
DELETE Yes No

Checking or modifying a value when trying to insert data makes the NEW.<column name> modifier available. This is because a table is updated with new content. In contrast, an OLD.<column name> value does not exist for an insert statement because there is no information exists in its place beforehand.

When updating a table row, both modifiers are available. There is OLD.<colum name> data which we want to update to NEW.<column name> data.

Finally, when removing a row of data, the OLD.<column name> modifier accesses the removed value. The NEW.<column name> does not exist because nothing is replacing the old value upon removal.

MySQL Trigger Example

As an example of an applied trigger, inserting new values into the table person yields a different result than the original input:

Inserting into a database with a trigger

Notice the inserted names were initially lowercase. When selecting the table, the first letter shows as capitalized. Even though there is no indication of anything different from a regular insert statement, the trigger fired before the insert statement to capitalize the first letter of the name.

Using MySQL Triggers

Every trigger associated with a table has a unique name and function based on two factors:

1. Time. BEFORE or AFTER a specific row event.

2. Event. INSERT, UPDATE or DELETE.

MySQL Triggers

MySQL triggers fire depending on the activation time and the event for a total of six unique trigger combinations. The before statements help to check data and make changes before making commitments, whereas the after statements commit the data first and then execute statements.

The execution of a set of actions happens automatically, affecting all inserted, deleted, or updated rows in the statement.

Create Triggers

Use the CREATE TRIGGER statement syntax to create a new trigger:

CREATE TRIGGER <trigger name> <trigger time > <trigger event>
ON <table name>
FOR EACH ROW
<trigger body>;

The best practice is to name the trigger with the following information:

<trigger time>_<table name>_<trigger event>

For example, if a trigger fires before insert on a table named employee, the best convention is to call the trigger:

before_employee_insert

Alternatively, a common practice is to use the following format:

<table name>_<first letter of trigger time><first letter of trigger name>

The before insert trigger name for the table employee looks like this:

employee_bi

The trigger executes at a specific time of an event on a table defined by <table name> for each row affected by the function.

Delete Triggers

To delete a trigger, use the DROP TRIGGER statement:

DROP TRIGGER <trigger name>;
Drop trigger command output

Alternatively, use:

DROP TRIGGER IF EXISTS <trigger name>;
Drop trigger error message output

The error message does not display because there is no trigger, so no warning prints.

Create Example Database

Create a database for the trigger example codes with the following structure:

1. Create a table called person with name and age for columns.

CREATE TABLE person (name varchar(45), age int);

Insert sample data into the table:

INSERT INTO person VALUES ('Matthew', 25), ('Mark', 20);

Select the table to see the result:

SELECT * FROM person;
Create table person

2. Create a table called average_age with a column called average:

CREATE TABLE average_age (average double);

Insert the average age value into the table:

INSERT INTO average_age SELECT AVG(age) FROM person;

Select the table to see the result:

SELECT * FROM average_age;
Create table average_age

3. Create a table called person_archive with name, age, and time columns:

CREATE TABLE person_archive (
name varchar(45),
age int,
time timestamp DEFAULT NOW());
Create table person_archive

Create a BEFORE INSERT Trigger

To create a BEFORE INSERT trigger, use:

CREATE TRIGGER <trigger name> BEFORE INSERT
ON <table name>
FOR EACH ROW
<trigger body>;

The BEFORE INSERT trigger gives control over data modification before committing into a database table. Capitalizing names for consistency, checking the length of an input, or catching faulty inputs with BEFORE INSERT triggers further provides value limitations before entering new data.

BEFORE INSERT Trigger Example

Create a BEFORE INSERT trigger to check the age value before inserting data into the person table:

delimiter //
CREATE TRIGGER person_bi BEFORE INSERT
ON person
FOR EACH ROW
IF NEW.age < 18 THEN
SIGNAL SQLSTATE '50001' SET MESSAGE_TEXT = 'Person must be older than 18.';
END IF; //
delimiter ;
Create before insert trigger

Inserting data activates the trigger and checks the value of age before committing the information:

INSERT INTO person VALUES ('John', 14);
Before insert trigger result

The console displays the descriptive error message. The data does not insert into the table because of the failed trigger check.

Create an AFTER INSERT Trigger

Create an AFTER INSERT trigger with:

CREATE TRIGGER <trigger name> AFTER INSERT
ON <table name>
FOR EACH ROW
<trigger body>;

The AFTER INSERT trigger is useful when the entered row generates a value needed to update another table.

AFTER INSERT Trigger Example

Inserting a new row into the person table does not automatically update the average in the average_age table. Create an AFTER INSERT trigger on the person table to update the average_age table after insert:

delimiter //
CREATE TRIGGER person_ai AFTER INSERT
ON person
FOR EACH ROW
UPDATE average_age SET average = (SELECT AVG(age) FROM person); //
delimiter ;
create after insert trigger

Inserting a new row into the person table activates the trigger:

INSERT INTO person VALUES ('John', 19);
After insert trigger results

The data successfully commits to the person table and updates the average_age table with the correct average value.

Create a BEFORE UPDATE Trigger

Make a BEFORE UPDATE trigger with:

CREATE TRIGGER <trigger name> BEFORE UPDATE
ON <table name>
FOR EACH ROW
<trigger body>;

The BEFORE UPDATE triggers go together with the BEFORE INSERT triggers. If any restrictions exist before inserting data, the limits should be there before updating as well.

BEFORE UPDATE Trigger Example

If there is an age restriction for the person table before inserting data, the age restriction should also exist before updating information. Without the BEFORE UPDATE trigger, the age check trigger is easy to avoid. Nothing restricts editing to a faulty value.

Add a BEFORE UPDATE trigger to the person table with the same body as the BEFORE INSERT trigger:

delimiter //
CREATE TRIGGER person_bu BEFORE UPDATE
ON person
FOR EACH ROW
IF NEW.age < 18 THEN
SIGNAL SQLSTATE '50002' SET MESSAGE_TEXT = 'Person must be older than 18.';
END IF; //
delimiter ;
Create before update trigger

Updating an existing value activates the trigger check:

UPDATE person SET age = 17 WHERE name = 'John';
before update trigger results

Updating the age to a value less than 18 displays the error message, and the information does not update.

Create an AFTER UPDATE Trigger

Use the following code block to create an AFTER UPDATE trigger:

CREATE TRIGGER <trigger name> AFTER UPDATE
ON <table name>
FOR EACH ROW
<trigger body>;

The AFTER UPDATE trigger helps keep track of committed changes to data. Most often, any changes after inserting information also happen after updating data.

AFTER UPDATE Trigger Example

Any successful updates to the age data in the table person should also update the intermediate average value calculated in the average_age table.

Create an AFTER UPDATE trigger to update the average_age table after updating a row in the person table:

delimiter //
CREATE TRIGGER person_au AFTER UPDATE
ON person
FOR EACH ROW
UPDATE average_age SET average = (SELECT AVG(age) FROM person); //
delimiter ;
Create after update trigger

Updating existing data changes the value in the person table:

UPDATE person SET age = 21 WHERE name = 'John';
After update trigger results

Updating the table person also updates the average in the average_age table.

Create a BEFORE DELETE Trigger

To create a BEFORE DELETE trigger, use:

CREATE TRIGGER <trigger name> BEFORE DELETE
ON <table name>
FOR EACH ROW
<trigger body>;

The BEFORE DELETE trigger is essential for security reasons. If a parent table has any children attached, the trigger helps block deletion and prevents orphaned tables. The trigger also allows archiving data before deletion.

BEFORE DELETE Trigger Example

Archive deleted data by creating a BEFORE DELETE trigger on the table person and insert the values into the person_archive table:

delimiter //
CREATE TRIGGER person_bd BEFORE DELETE
ON person
FOR EACH ROW
INSERT INTO person_archive (name, age)
VALUES (OLD.name, OLD.age); //
delimiter ;
Create before delete trigger

Deleting data from the table person archives the data into the person_archive table before deleting:

DELETE FROM person WHERE name = 'John';
before delete trigger result

Inserting the value back into the person table keeps the log of the deleted data in the person_archive table:

INSERT INTO person VALUES ('John', 21);
person_archive unchanged after insert

The BEFORE DELETE trigger is useful for logging any table change attempts.

Create an AFTER DELETE Trigger

Make an AFTER DELETE trigger with:

CREATE TRIGGER <trigger name> AFTER DELETE
ON <table name>
FOR EACH ROW
<trigger body>;

The AFTER DELETE triggers maintain information updates that require the data row to disappear before making the updates.

AFTER DELETE Trigger Example

Create an AFTER DELETE trigger on the table person to update the average_age table with the new information:

delimiter //
CREATE TRIGGER person_ad AFTER DELETE
ON person
FOR EACH ROW
UPDATE average_age SET average = (SELECT AVG(person.age) FROM person); //
delimiter ;
Create after delete trigger

Deleting a record from the table person updates the average_age table with the new average:

After delete trigger results

Without the AFTER DELETE trigger, the information does not update automatically.

Create Multiple Triggers

MySQL does not support having multiple triggers fire at the same time. However, adding multiple logical operations to the same trigger is possible. Use the BEGIN and END delimiters to indicate the trigger body:

CREATE TRIGGER <trigger name> <trigger time > <trigger event>
ON <table name>
FOR EACH ROW
BEGIN
<trigger body>;
END;

Make sure to change the default delimiter before creating a trigger with multiple operations.

Show Triggers

List all the triggers in a database with:

SHOW triggers;

The output shows a list of all the triggers, including the name and statement contents:

Output of show triggers

Other information displays as well, such as the creation time and the user who created the trigger.

Conclusion

MySQL triggers provide further validation and control of data before or after specific events happen. Whether you are trying to prevent an error or add restrictions for consistency, triggers help control data input, update, and removal.

Keep in mind the trigger checks happen row-wise, which causes performance to slow down with massive queries. For more materials on this topic, check out our article on how to improve MySQL performance with tuning.

Last update on August 19 2022 21:50:42 (UTC/GMT +8 hours)

Introduction on Triggers

A trigger is a set of actions that are run automatically when a specified change operation (SQL INSERT, UPDATE, or DELETE statement) is performed on a specified table. Triggers are useful for tasks such as enforcing business rules, validating input data, and keeping an audit trail.

Contents:

  • Uses for triggers
  • Benefits of using triggers in business
  • MySQL Triggers
  • Create MySQL triggers
  • Sample database, table, table structure, table records
  • Tool to create MySQL Triggers
  • MySQL Trigger : Example AFTER INSERT
  • MySQL Trigger : Example BEFORE INSERT
  • MySQL Trigger : Example AFTER UPDATE
  • MySQL Trigger : Example BEFORE UPDATE
  • MySQL Trigger : Example AFTER DELETE
  • How MySQL handle errors during trigger execution?
  • Delete a MySQL trigger

Uses for triggers:

  • Enforce business rules
  • Validate input data
  • Generate a unique value for a newly-inserted row in a different file.
  • Write to other files for audit trail purposes
  • Query from other files for cross-referencing purposes
  • Access system functions
  • Replicate data to different files to achieve data consistency

Benefits of using triggers in business:

  • Faster application development. Because the database stores triggers, you do not have to code the trigger actions into each database application.
  • Global enforcement of business rules. Define a trigger once and then reuse it for any application that uses the database.
  • Easier maintenance. If a business policy changes, you need to change only the corresponding trigger program instead of each application program.
  • Improve performance in client/server environment. All rules run on the server before the result returns.

Implementation of SQL triggers is based on the SQL standard. It supports constructs that are common to most programming languages. It supports the declaration of local variables, statements to control the flow of the procedure, assignment of expression results to variables, and error handling.

MySQL Triggers

We assume that you are habituated with «MySQL Stored Procedures», if not you can read our MySQL Procedures tutorial. You can use the following statements of MySQL procedure in triggers:

  • Compound statements (BEGIN / END)
  • Variable declaration (DECLARE) and assignment (SET)
  • Flow-of-control statements (IF, CASE, WHILE, LOOP, WHILE, REPEAT, LEAVE, ITERATE)
  • Condition declarations
  • Handler declarations

How to create MySQL triggers?

A trigger is a named database object that is associated with a table, and it activates when a particular event (e.g. an insert, update or delete) occurs for the table. The statement CREATE TRIGGER creates a new trigger in MySQL. Here is the syntax :

Syntax:

CREATE     
[DEFINER = { user | CURRENT_USER }]     
TRIGGER trigger_name     
trigger_time trigger_event     
ON tbl_name FOR EACH ROW     
trigger_body
trigger_time: { BEFORE | AFTER } 
trigger_event: { INSERT | UPDATE | DELETE }

Explanation:

DEFINER clause: The DEFINER clause specifies the MySQL account to be used when checking access privileges at trigger activation time. If a user value is given, it should be a MySQL account specified as ‘user_name’@’host_name’ (the same format used in the GRANT statement), CURRENT_USER, or CURRENT_USER().
The default DEFINER value is the user who executes the CREATE TRIGGER statement. This is the same as specifying DEFINER = CURRENT_USER explicitly.
If you specify the DEFINER clause, these rules determine the valid DEFINER user values:

  • If you do not have the SUPER privilege, the only permitted user value is your own account, either specified literally or by using CURRENT_USER. You cannot set the definer to some other account.
  • If you have the SUPER privilege, you can specify any syntactically valid account name. If the account does not actually exist, a warning is generated.
  • Although it is possible to create a trigger with a nonexistent DEFINER account, it is not a good idea for such triggers to be activated until the account actually does exist. Otherwise, the behavior with respect to privilege checking is undefined.

trigger_name: All triggers must have unique names within a schema. Triggers in different schemas can have the same name.

trigger_time: trigger_time is the trigger action time. It can be BEFORE or AFTER to indicate that the trigger activates before or after each row to be modified.

trigger_event: trigger_event indicates the kind of operation that activates the trigger. These trigger_event values are permitted:

  • The trigger activates whenever a new row is inserted into the table; for example, through INSERT, LOAD DATA, and REPLACE statements.
  • The trigger activates whenever a row is modified; for example, through UPDATE statements.
  • The trigger activates whenever a row is deleted from the table; for example, through DELETE and REPLACE statements. DROP TABLE and TRUNCATE TABLE statements on the table do not activate this trigger, because they do not use DELETE. Dropping a partition does not activate DELETE triggers, either.

tbl_name : The trigger becomes associated with the table named tbl_name, which must refer to a permanent table. You cannot associate a trigger with a TEMPORARY table or a view.

trigger_body: trigger_body is the statement to execute when the trigger activates. To execute multiple statements, use the BEGIN … END compound statement construct. This also enables you to use the same statements that are permissible within stored routines.

Here is a simple example:

mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;
Query OK, 0 rows affected (0.06 sec)

In the above example, there is new keyword ‘NEW‘ which is a MySQL extension to triggers. There is two MySQL extension to triggers ‘OLD‘ and ‘NEW‘. OLD and NEW are not case sensitive.

  • Within the trigger body, the OLD and NEW keywords enable you to access columns in the rows affected by a trigger
  • In an INSERT trigger, only NEW.col_name can be used.
  • In a UPDATE trigger, you can use OLD.col_name to refer to the columns of a row before it is updated and NEW.col_name to refer to the columns of the row after it is updated.
  • In a DELETE trigger, only OLD.col_name can be used; there is no new row.

A column named with OLD is read only. You can refer to it (if you have the SELECT privilege), but not modify it. You can refer to a column named with NEW if you have the SELECT privilege for it. In a BEFORE trigger, you can also change its value with SET NEW.col_name = value if you have the UPDATE privilege for it. This means you can use a trigger to modify the values to be inserted into a new row or used to update a row. (Such a SET statement has no effect in an AFTER trigger because the row change will have already occurred.)

Sample database, table, table structure, table records for various examples

Database Name: hr
Host Name : localhost
Database user : root
Password : ‘ ‘

Structure of the table : emp_details

table user details

Records of the table (on some fields): emp_details

mysql> SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;
+-------------+------------+-----------+---------+----------+----------------+ | EMPLOYEE_ID | FIRST_NAME | LAST_NAME | JOB_ID | SALARY | COMMISSION_PCT | +-------------+------------+-----------+---------+----------+----------------+ | 100 | Steven | King | AD_PRES | 24000.00 | 0.10 | | 101 | Neena | Kochhar | AD_VP | 17000.00 | 0.50 | | 102 | Lex | De Haan | AD_VP | 17000.00 | 0.50 | | 103 | Alexander | Hunold | IT_PROG | 9000.00 | 0.25 | | 104 | Bruce | Ernst | IT_PROG | 6000.00 | 0.25 | | 105 | David | Austin | IT_PROG | 4800.00 | 0.25 | +-------------+------------+-----------+---------+----------+----------------+
6 rows in set (0.00 sec)

Tool to create MySQL Triggers

You can write a procedure in MySQL command line tool or you can use MySQL workbench which is an excellent front-end tool (here we have used version 5.3 CE).

MySQL command line tool: —

Select MySQL command Client from Start menu:

MySQL command prompt

Selecting MySQL command prompt following screen will come:

mysql5.6 command prompt password

After a successful login, you can access the MySQL command prompt:

mysql5.6 command line client

Now you can write your own trigger on a specific table, see the following example :

mysql create trigge in command line

MySQL workbench (5.3 CE): —

Select MySQL workbench from Start menu :

mysql workbench start

After selecting MySQL workbench following login screen will come:

mysql workbench 5.2

Now input the login details :

mysql 5.6 workbench login

After successful login, a new screen will come and from the object browser panel select a database:

mysql 5.6 workbench select database

After selecting the database, select the tables:

mysql triger select table in workbench

Now right click on emp_details a window pops up, click on Alter Table:

mysql trigger select  alter

Clicking on » Alter Table » details of emp_details will come:

mysql work bench alter table and select trigger

Now click on Trigger tab in the previous section, then select the Timing/Event it may be AFTER DELETE, AFTER INSERT, AFTER UPDATE or BEFORE DELETE, BEFORE INSERT OR BEFORE UPDATE. Let we select AFTER INSERT, you also notice that there is a button Add Trigger.

mysql workbench select timing/event

Clicking on Add Trigger button a default code on trigger will come on the basis of choosing Timing/Event:

mysql workbench create trigger

Trigger Name: emp_details_AINS
Default Trigger code details:

USE `hr`;
DELIMITER 
$$
CREATE TRIGGER `emp_details_AINS` 
AFTER INSERT 
ON emp_details FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one

After completing the code, click on apply button.

Note: See a new text Delete Trigger has come in Add Trigger button. Clicking on this you can delete the trigger.

Finally you can review the script once again, as there is no error, let click on Apply button:

mysql workbench save trigger

This the final window before finish. Let click on Finish button.

mysq -workbench finish trigger

If you take a look at the schema, you will see emp_details_AINS trigger under the emp_details table as follows:

mysql schema with triggers

MySQL Trigger : Example AFTER INSERT

In the following example, we have two tables: emp_details and log_emp_details. To insert some information into log_ emp_details table (which have three fields employee id and salary and edttime) every time, when an INSERT happen into emp_details table we have used the following trigger :

DELIMITER 
$$
USE `hr`
$$
CREATE 
DEFINER=`root`@`127.0.0.1` 
TRIGGER `hr`.`emp_details_AINS` 
AFTER INSERT ON `hr`.`emp_details`
FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN 
INSERT INTO log_emp_details 
VALUES(NEW.employee_id, NEW.salary, NOW());
END$$

Records of the table (on some columns) : emp_details

mysql> SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;
+-------------+------------+-----------+---------+----------+----------------+
| EMPLOYEE_ID | FIRST_NAME | LAST_NAME | JOB_ID  | SALARY   | COMMISSION_PCT |
+-------------+------------+-----------+---------+----------+----------------+
|         100 | Steven     | King      | AD_PRES | 24000.00 |           0.10 |
|         101 | Neena      | Kochhar   | AD_VP   | 17000.00 |           0.50 |
|         102 | Lex        | De Haan   | AD_VP   | 17000.00 |           0.50 |
|         103 | Alexander  | Hunold    | IT_PROG |  9000.00 |           0.25 |
|         104 | Bruce      | Ernst     | IT_PROG |  6000.00 |           0.25 |
|         105 | David      | Austin    | IT_PROG |  4800.00 |           0.25 |
+-------------+------------+-----------+---------+----------+----------------+
6 rows in set (0.00 sec)

Records of the table (all columns) : log_emp_details

mysql> SELECT * FROM log_emp_details;
+-------------+----------+---------------------+
| emp_details | SALARY   | EDTTIME             |
+-------------+----------+---------------------+
|         100 | 24000.00 | 2011-01-15 00:00:00 |
|         101 | 17000.00 | 2010-01-12 00:00:00 |
|         102 | 17000.00 | 2010-09-22 00:00:00 |
|         103 |  9000.00 | 2011-06-21 00:00:00 |
|         104 |  6000.00 | 2012-07-05 00:00:00 |
|         105 |  4800.00 | 2011-06-21 00:00:00 |
+-------------+----------+---------------------+
6 rows in set (0.02 sec)

Now insert one record in emp_details table see the records both in emp_details and log_emp_details tables :

mysql> INSERT INTO emp_details VALUES(236, 'RABI', 'CHANDRA', 'RABI','590.423.45700', '2013-01-12', 'AD_VP', 15000, .5);
Query OK, 1 row affected (0.07 sec)
mysql> SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;
+-------------+------------+-----------+---------+----------+----------------+
| EMPLOYEE_ID | FIRST_NAME | LAST_NAME | JOB_ID  | SALARY   | COMMISSION_PCT |
+-------------+------------+-----------+---------+----------+----------------+
|         100 | Steven     | King      | AD_PRES | 24000.00 |           0.10 |
|         101 | Neena      | Kochhar   | AD_VP   | 17000.00 |           0.50 |
|         102 | Lex        | De Haan   | AD_VP   | 17000.00 |           0.50 |
|         103 | Alexander  | Hunold    | IT_PROG |  9000.00 |           0.25 |
|         104 | Bruce      | Ernst     | IT_PROG |  6000.00 |           0.25 |
|         105 | David      | Austin    | IT_PROG |  4800.00 |           0.25 |
|         236 | RABI       | CHANDRA   | AD_VP   | 15000.00 |           0.50 |
+-------------+------------+-----------+---------+----------+----------------+
7 rows in set (0.00 sec)
mysql> SELECT * FROM log_emp_details;
+-------------+----------+---------------------+
| emp_details | SALARY   | EDTTIME             |
+-------------+----------+---------------------+
|         100 | 24000.00 | 2011-01-15 00:00:00 |
|         101 | 17000.00 | 2010-01-12 00:00:00 |
|         102 | 17000.00 | 2010-09-22 00:00:00 |
|         103 |  9000.00 | 2011-06-21 00:00:00 |
|         104 |  6000.00 | 2012-07-05 00:00:00 |
|         105 |  4800.00 | 2011-06-21 00:00:00 |
|         236 | 15000.00 | 2013-07-15 16:52:24 |
+-------------+----------+---------------------+
7 rows in set (0.00 sec)

MySQL Trigger : Example BEFORE INSERT

In the following example, before insert a new record in emp_details table, a trigger check the column value of FIRST_NAME, LAST_NAME, JOB_ID and
— If there are any space(s) before or after the FIRST_NAME, LAST_NAME, TRIM() function will remove those.
— The value of the JOB_ID will be converted to upper cases by UPPER() function.

Here is the trigger code :

USE `hr`;
DELIMITER 
$$
CREATE TRIGGER `emp_details_BINS` 
BEFORE INSERT 
ON emp_details FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN
SET NEW.FIRST_NAME = TRIM(NEW.FIRST_NAME);
SET NEW.LAST_NAME = TRIM(NEW.LAST_NAME);
SET NEW.JOB_ID = UPPER(NEW.JOB_ID);END;
$$

Now insert a row into emp_details table (check the FIRST_NAME, LAST_NAME, JOB_ID columns) :

mysql> INSERT INTO emp_details VALUES (334, ' Ana ', ' King', 'ANA', '690.432.45701', '2013-02-05', 'it_prog', 17000, .50);
Query OK, 1 row affected (0.04 sec)

Now list the following fields of emp_details :

mysql> SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB_ID, SALARY, COMMISSION_PCT FROM emp_details;
+-------------+------------+-----------+---------+----------+----------------+
| EMPLOYEE_ID | FIRST_NAME | LAST_NAME | JOB_ID  | SALARY   | COMMISSION_PCT |
+-------------+------------+-----------+---------+----------+----------------+
|         100 | Steven     | King      | AD_PRES | 24000.00 |           0.10 |
|         101 | Neena      | Kochhar   | AD_VP   | 17000.00 |           0.50 |
|         102 | Lex        | De Haan   | AD_VP   | 17000.00 |           0.50 |
|         103 | Alexander  | Hunold    | IT_PROG |  9000.00 |           0.25 |
|         104 | Bruce      | Ernst     | IT_PROG |  6000.00 |           0.25 |
|         105 | David      | Austin    | IT_PROG |  4800.00 |           0.25 |
|         236 | RABI       | CHANDRA   | AD_VP   | 15000.00 |           0.50 |
|         334 | Ana        | King      | IT_PROG | 17000.00 |           0.50 |
+-------------+------------+-----------+---------+----------+----------------+
8 rows in set (0.00 sec)

See the last row :

FIRST_NAME — > ‘ Ana ‘ has changed to ‘Ana’
LAST_NAME — > ‘ King’ has changed to ‘King’
JOB_ID — > ‘ it_prog’ has changed to ‘IT_PROG’

MySQL Trigger : Example AFTER UPDATE

We have two tables student_mast and stu_log. student_mast have three columns STUDENT_ID, NAME, ST_CLASS. stu_log table has two columns user_id and description.

mysql> SELECT * FROM STUDENT_MAST;
+------------+------------------+----------+
| STUDENT_ID | NAME             | ST_CLASS |
+------------+------------------+----------+
|          1 | Steven King      |        7 |
|          2 | Neena  Kochhar   |        8 |
|          3 | Lex  De Haan     |        8 |
|          4 | Alexander Hunold |       10 |
+------------+------------------+----------+
4 rows in set (0.00 sec)

Let we promote all the students in next class i.e. 7 will be 8, 8 will be 9 and so on. After updating a single row in student_mast table a new row will be inserted in stu_log table where we will store the current user id and a small description regarding the current update. Here is the trigger code :

-- Full Trigger 
DDL Statements
-- Note: Only CREATE TRIGGER statements are allowed
DELIMITER 
$$
USE `test`
$$
CREATE 
DEFINER=`root`@`127.0.0.1`
TRIGGER `test`.`student_mast_AUPD`
AFTER UPDATE 
ON `test`.`student_mast`FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN
INSERT into stu_log VALUES (user(), CONCAT('Update Student Record ',
         OLD.NAME,' Previous Class :',OLD.ST_CLASS,' Present Class ',
         NEW.st_class));
END
$$

After update STUDENT_MAST table :

mysql> UPDATE STUDENT_MAST SET ST_CLASS = ST_CLASS + 1;
Query OK, 4 rows affected (0.20 sec)
Rows matched: 4  
Changed: 4  
Warnings: 0

The trigger show you the updated records in ‘stu_log’. Here is the latest position of STUDENT_MAST and STU_LOG tables :

mysql> SELECT * FROM STUDENT_MAST;
+------------+------------------+----------+
| STUDENT_ID | NAME             | ST_CLASS |
+------------+------------------+----------+
|          1 | Steven King      |        8 |
|          2 | Neena  Kochhar   |        9 |
|          3 | Lex  De Haan     |        9 |
|          4 | Alexander Hunold |       11 |
+------------+------------------+----------+
4 rows in set (0.00 sec)mysql> SELECT * FROM STU_LOG;
+----------------+---------------------------------------------------------------------------+
| user_id        | description                                                               |
+----------------+---------------------------------------------------------------------------+
| [email protected] | Update Student Record Steven King Previous Class :7 Present Class 8       |
| [email protected] | Update Student Record Neena  Kochhar Previous Class :8 Present Class 9    |
| [email protected] | Update Student Record Lex  De Haan Previous Class :8 Present Class 9      |
| [email protected] | Update Student Record Alexander Hunold Previous Class :10 Present Class 11|
+----------------+---------------------------------------------------------------------------+
4 rows in set (0.00 sec)

MySQL Trigger : Example BEFORE UPDATE

We have a table student_marks with 10 columns and 4 rows. There are data only in STUDENT_ID and NAME columns.

mysql> SELECT * FROM STUDENT_MARKS;
+------------+------------------+------+------+------+------+------+-------+-----------+-------+
| STUDENT_ID | NAME             | SUB1 | SUB2 | SUB3 | SUB4 | SUB5 | TOTAL | PER_MARKS | GRADE |
+------------+------------------+------+------+------+------+------+-------+-----------+-------+
|          1 | Steven King      |    0 |    0 |    0 |    0 |    0 |     0 |      0.00 |       |
|          2 | Neena  Kochhar   |    0 |    0 |    0 |    0 |    0 |     0 |      0.00 |       |
|          3 | Lex  De Haan     |    0 |    0 |    0 |    0 |    0 |     0 |      0.00 |       |
|          4 | Alexander Hunold |    0 |    0 |    0 |    0 |    0 |     0 |      0.00 |       |
+------------+------------------+------+------+------+------+------+-------+-----------+-------+
4 rows in set (0.00 sec)

Now the exam is over and we have received all subject marks, now we will update the table, total marks of all subject, the percentage of total marks and grade will be automatically calculated. For this sample calculation, the following conditions are assumed :

Total Marks (will be stored in TOTAL column) : TOTAL = SUB1 + SUB2 + SUB3 + SUB4 + SUB5

Percentage of Marks (will be stored in PER_MARKS column) : PER_MARKS = (TOTAL)/5

Grade (will be stored GRADE column) :
— If PER_MARKS>=90 -> ‘EXCELLENT’
— If PER_MARKS>=75 AND PER_MARKS<90 -> ‘VERY GOOD’
— If PER_MARKS>=60 AND PER_MARKS<75 -> ‘GOOD’
— If PER_MARKS>=40 AND PER_MARKS<60 -> ‘AVERAGE’
— If PER_MARKS<40-> ‘NOT PROMOTED’

Here is the code :

mysql> UPDATE STUDENT_MARKS SET SUB1 = 54, SUB2 = 69, SUB3 = 89, SUB4 = 87, SUB5 = 59 WHERE STUDENT_ID = 1;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  
Changed: 1  
Warnings: 0

Let update the marks of a student :

USE `test`;
DELIMITER 
$$
CREATE TRIGGER `student_marks_BUPD` 
BEFORE UPDATE 
ON student_marks FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN 
SET NEW.TOTAL = NEW.SUB1 + NEW.SUB2 + NEW.SUB3 + NEW.SUB4 + NEW.SUB5; 
SET NEW.PER_MARKS = NEW.TOTAL/5;
IF NEW.PER_MARKS >=90 THEN
SET NEW.GRADE = 'EXCELLENT';
ELSEIF NEW.PER_MARKS>=75 AND NEW.PER_MARKS<90 THEN
SET NEW.GRADE = 'VERY GOOD';
ELSEIF NEW.PER_MARKS>=60 AND NEW.PER_MARKS<75 THEN
SET NEW.GRADE = 'GOOD';
ELSEIF NEW.PER_MARKS>=40 AND NEW.PER_MARKS<60 THEN
SET NEW.GRADE = 'AVERAGE';
ELSESET NEW.GRADE = 'NOT PROMOTED';
END IF;
END;
$$

Now check the STUDENT_MARKS table with updated data. The trigger show you the updated records in ‘stu_log’.

mysql> SELECT * FROM STUDENT_MARKS;
+------------+------------------+------+------+------+------+------+-------+-----------+-------+
| STUDENT_ID | NAME             | SUB1 | SUB2 | SUB3 | SUB4 | SUB5 | TOTAL | PER_MARKS | GRADE |
+------------+------------------+------+------+------+------+------+-------+-----------+-------+
|          1 | Steven King      |   54 |   69 |   89 |   87 |   59 |   358 |     71.60 | GOOD  |
|          2 | Neena  Kochhar   |    0 |    0 |    0 |    0 |    0 |     0 |      0.00 |       |
|          3 | Lex  De Haan     |    0 |    0 |    0 |    0 |    0 |     0 |      0.00 |       |
|          4 | Alexander Hunold |    0 |    0 |    0 |    0 |    0 |     0 |      0.00 |       |
+------------+------------------+------+------+------+------+------+-------+-----------+-------+
4 rows in set (0.00 sec)

MySQL Trigger : Example AFTER DELETE

In our ‘AFTER UPDATE’ example, we had two tables student_mast and stu_log. student_mast have three columns STUDENT_ID, NAME, ST_CLASS and stu_log table has two columns user_id and description. We want to store some information in stu_log table after a delete operation happened on student_mast table. Here is the trigger :

USE `test`;
DELIMITER 
$$
CREATE TRIGGER `student_mast_ADEL` 
AFTER DELETE ON student_mast FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN
INSERT into stu_log VALUES (user(), CONCAT('Update Student Record ',
         OLD.NAME,' Clas :',OLD.ST_CLASS, '-> Deleted on ', NOW()));
END;
$$

Let delete a student from STUDENT_MAST.

mysql> DELETE FROM STUDENT_MAST WHERE STUDENT_ID = 1;
Query OK, 1 row affected (0.06 sec)

Here is the latest position of STUDENT_MAST, STU_LOG tables :

mysql> SELECT * FROM STUDENT_MAST;
+------------+------------------+----------+
| STUDENT_ID | NAME             | ST_CLASS |
+------------+------------------+----------+
|          2 | Neena  Kochhar   |        9 |
|          3 | Lex  De Haan     |        9 |
|          4 | Alexander Hunold |       11 |
+------------+------------------+----------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM STU_LOG;
+----------------+-----------------------------------------------------------------------------+
| user_id        | description                                                                 |
+----------------+-----------------------------------------------------------------------------+
| [email protected] | Update Student RecordSteven King Previous Class :7 Present Class 8          |
| [email protected] | Update Student RecordNeena  Kochhar Previous Class :8 Present Class 9       |
| [email protected] | Update Student RecordLex  De Haan Previous Class :8 Present Class 9         |
| [email protected] | Update Student RecordAlexander Hunold Previous Class :10 Present Class 11   |
| [email protected] | Update Student Record Steven King Clas :8-> Deleted on 2013-07-16 15:35:30  |
+----------------+-----------------------------------------------------------------------------+
5 rows in set (0.00 sec)

How MySQL handle errors during trigger execution?

  • If a BEFORE trigger fails, the operation on the corresponding row is not performed.
  • A BEFORE trigger is activated by the attempt to insert or modify the row, regardless of whether the attempt subsequently succeeds.
  • An AFTER trigger is executed only if any BEFORE triggers and the row operation execute successfully.
  • An error during either a BEFORE or AFTER trigger results in failure of the entire statement that caused trigger invocation.
  • For transactional tables, failure of a statement should cause a rollback of all changes performed by the statement.

Delete a MySQL trigger

To delete or destroy a trigger, use a DROP TRIGGER statement. You must specify the schema name if the trigger is not in the default (current) schema :

DROP TRIGGER [IF EXISTS] [schema_name.]trigger_nam

if you drop a table, any triggers for the table are also dropped.

Reference: MySQL 5.6 Manual

Previous:
MySQL Procedure
Next:
MySQL Transaction

Понравилась статья? Поделить с друзьями:
  • Tribal error скачать торрент
  • Truice sql error
  • Trial error fighter
  • Truedepth камера ошибка
  • Trial error cried wolf feat katie laffan