ТРИГГЕРЫ, которые приводят к сбою INSERT? Возможный?

При очистке этот ответ я немного узнал о TRIGGER и хранимых процедурах в MySQL, но был ошеломлен тем, что, хотя триггеры BEFORE INSERT и BEFORE UPDATE могли изменять данные, они, по-видимому, не могли привести к сбою вставки / обновления (т. Е. Проверки). В этом конкретном случае мне удалось заставить это работать, манипулируя данными таким образом, чтобы вызвать дублирование первичного ключа, что в данном конкретном случае имело смысл, но не обязательно имеет смысл в общем смысле.

Возможна ли такая функциональность в MySQL? В любой другой СУБД (к сожалению, мой опыт ограничен MySQL)? Может быть, синтаксис в стиле THROW EXCEPTION?

из MySQL 5.5, возможно, ранее, вы можете использовать сигналы, [см. мой ответ здесь] [1] [1]: stackoverflow.com/questions/24/throw-error-in-mysql-trigger/‌…

RuiDC 25.08.2011 15:18
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
14
1
22 705
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Из этого Сообщение блога

MySQL Triggers: How do you abort an INSERT, UPDATE or DELETE with a trigger? On EfNet’s #mysql someone asked:

How do I make a trigger abort the operation if my business rule fails?

In MySQL 5.0 and 5.1 you need to resort to some trickery to make a trigger fail and deliver a meaningful error message. The MySQL Stored Procedure FAQ says this about error handling:

SP 11. Do SPs have a “raise” statement to “raise application errors”? Sorry, not at present. The SQL standard SIGNAL and RESIGNAL statements are on the TODO.

Perhaps MySQL 5.2 will include SIGNAL statement which will make this hack stolen straight from MySQL Stored Procedure Programming obsolete. What is the hack? You’re going to force MySQL to attempt to use a column that does not exist. Ugly? Yes. Does it work? Sure.

CREATE TRIGGER mytabletriggerexample
BEFORE INSERT
FOR EACH ROW BEGIN
IF(NEW.important_value) < (fancy * dancy * calculation) THEN
    DECLARE dummy INT;

    SELECT Your meaningful error message goes here INTO dummy 
        FROM mytable
      WHERE mytable.id=new.id
END IF; END;

Я действительно рассмеялся, читая этот пример ... Это потрясающий прием, который работает с отчетами об ошибках MySQL ... Надеюсь, что скоро появится SIGNAL.

Matthew Scharley 23.10.2008 18:02

Это так здорово. Я устанавливал для некоторого столбца NOT NULL значение NULL, но это решение выдает значимое сообщение об ошибке. +1!

Bill Karwin 23.10.2008 20:17

Это не работает для меня, когда оператор объявления находится внутри условия. В документах написано: DECLARE разрешен только внутри составного оператора BEGIN ... END и должен находиться в его начале перед любыми другими операторами..

Ian Mackinnon 07.07.2012 18:19

Это прервет ваш INSERT, вызвав исключение (из http://www.experts-exchange.com/Database/MySQL/Q_23788965.html)

DROP PROCEDURE IF EXISTS `MyRaiseError`$$

CREATE PROCEDURE `MyRaiseError`(msg VARCHAR(62))
BEGIN
DECLARE Tmsg VARCHAR(80);
SET Tmsg = msg;
IF (CHAR_LENGTH(TRIM(Tmsg)) = 0 OR Tmsg IS NULL) THEN
SET Tmsg = 'ERROR GENERADO';
END IF;
SET Tmsg = CONCAT('@@MyError', Tmsg, '@@MyError');
SET @MyError = CONCAT('INSERT INTO', Tmsg);
PREPARE stmt FROM @MyError;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$

Использование:

call MyRaiseError('Here error message!');

в MS SQL вы можете заставить его работать, используя правильный синтаксис:

IF UPDATE(column_name)
BEGIN
  RAISEERROR
  ROLLBACK TRAN
  RETURN
END

http://msdn.microsoft.com/en-us/magazine/cc164047.aspx

Вот как я это сделал. Обратите внимание на SET NEW='some error';. MySQL сообщит вам, что «переменной 'new' не может быть присвоено значение 'Ошибка: невозможно удалить этот элемент. В таблице продаж есть записи с этим элементом'».

Вы можете перехватить это в своем коде, а затем показать полученную ошибку :)

DELIMITER $$
DROP TRIGGER IF EXISTS before_tblinventoryexceptionreasons_delete $$
CREATE TRIGGER before_tblinventoryexceptionreasons_delete
BEFORE DELETE ON tblinventoryexceptionreasons
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblinventoryexceptionreasons = old.idtblinventoryexceptionreasons) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory exception reasons table with this item.';
  END IF;
END$$
DELIMITER ;

DELIMITER $$
DROP TRIGGER IF EXISTS before_storesalesconfig_delete $$
CREATE TRIGGER before_storesalesconfig_delete
BEFORE DELETE ON tblstoresalesconfig
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblstoresales WHERE tblstoresales.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the sales table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinventory WHERE tblinventory.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinventoryexceptions WHERE tblinventoryexceptions.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory exceptions table with this item.';
  END IF;
  IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblstoresalesconfig=old.idtblstoresalesconfig) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
  END IF;
END$$
DELIMITER ;

DELIMITER $$
DROP TRIGGER IF EXISTS before_tblinvoice_delete $$
CREATE TRIGGER before_tblinvoice_delete
BEFORE DELETE ON tblinvoice
FOR EACH ROW BEGIN
  IF (SELECT COUNT(*) FROM tblinvoicedetails WHERE tblinvoicedetails.idtblinvoice = old.idtblinvoice) > 0
  THEN
    SET NEW='Error: Cannot delete this item. There are records in the inventory details table with this item.';
  END IF;
END$$
DELIMITER ;

Не работают в триггерах (Динамический SQL не разрешен в сохраненной функции или триггере)

Я использую очень грязный раствор:

If NEW.test=1 then CALL TEST_CANNOT_BE_SET_TO_1; end if;

Когда test = 1, Mysql выдает следующее исключение:

PROCEDURE administratie.TEST_CANNOT_BE_SET_TO_1 не существует

Не изощренно, но быстро и полезно.

Поскольку эта статья оказывается наверху, когда я ищу обработку ошибок в триггерах MySQL, я решил поделиться некоторыми знаниями.

Если есть ошибка, вы можете заставить MySQL использовать СИГНАЛ, но если вы не укажете его как класс как SQLEXCEPTION, тогда ничего не произойдет, так как не все SQLSTATE считаются плохими, и даже тогда вам придется обязательно RESIGNAL, если у вас есть вложенные блоки BEGIN / END.

В качестве альтернативы, что, вероятно, еще проще, в вашем триггере объявите обработчик выхода и откажитесь от исключения.

CREATE TRIGGER `my_table_AINS` AFTER INSERT ON `my_table` FOR EACH ROW
BEGIN
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
        RESIGNAL;
    DECLARE EXIT HANDLER FOR SQLWARNING
        RESIGNAL;
    DECLARE EXIT HANDLER FOR NOT FOUND
        RESIGNAL; 
    -- Do the work of the trigger.
END

И если в вашем теле произойдет ошибка, он будет отброшен вверх и выйдет с ошибкой. Это также можно использовать в хранимых процедурах и т. д.

Это работает с любой версией 5.5+.

Проголосовать за это, потому что это правильно, но, к сожалению, не все из нас также могут позволить себе роскошь работать с 5.5+. Ну что ж.

Matthew Scharley 06.10.2014 03:23

Другие вопросы по теме