MySQL Before Delete триггер, чтобы избежать удаления нескольких строк

Я пытаюсь избежать удаления более одной строки в MySQL за раз с помощью триггера BEFORE DELETE.

Примерная таблица и триггер приведены ниже.

Настольный тест:

DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `a` int(11) NOT NULL,
 `b` int(11) NOT NULL,
 PRIMARY KEY (`id`));


INSERT INTO `test` (`id`, `a`, `b`)
VALUES (1, 1, 2);

INSERT INTO `test` (`id`, `a`, `b`)
VALUES (2, 3, 4);

Курок:

DELIMITER //
DROP TRIGGER IF EXISTS prevent_multiple_deletion;
CREATE TRIGGER prevent_multiple_deletion
BEFORE DELETE ON test
FOR EACH STATEMENT 
BEGIN

  IF(ROW_COUNT()>=2) THEN  
    SIGNAL SQLSTATE '45000' 
    SET MESSAGE_TEXT = 'Cannot delete more than one order per time!';
  END IF;

END //

DELIMITER ;

Это по-прежнему позволяет удалять несколько строк. Даже если я изменю IF на> = 1, операция все равно будет разрешена.

Моя идея - избегать таких операций, как:

DELETE FROM `test` WHERE `id`< 5;

Вы можете мне помочь? Я знаю, что текущая версия MySQL не поддерживает триггеры FOR EACH STATEMENT.

Спасибо!

Я думаю, что ROW_COUNT() будет иметь значение 0 (затронутые строки) только в Перед удалением триггера. Поскольку до сих пор ни одна строка не была затронута.

Madhur Bhaiya 02.11.2018 15:40
Освоение архитектуры микросервисов с 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
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
1
1 731
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Во-первых, мы избавились от некоторых синтаксических ошибок из вашей исходной попытки:

  • Вместо FOR EACH STATEMENT должен быть FOR EACH ROW.
  • Поскольку вы уже определили разделитель для //; вам нужно использовать // (вместо ;) в операторе DROP TRIGGER IF EXISTS ...
  • Row_Count() будет иметь значение 0 в Before Delete Trigger, поскольку строки еще не обновлены. Так что этот подход не сработает.

Теперь уловка состоит в том, чтобы использовать Доступный (и постоянный) на уровне сеансапользовательские переменные. Мы можем определить переменную, скажем, @rows_being_deleted, и позже проверить, определена ли она уже или нет.

For Each Row запускает один и тот же набор операторов для каждой строки удаляется. Итак, мы просто проверим, существует ли уже переменная сеанса или нет. Если нет, мы можем определить это. Итак, в основном, для первой строки (удаляемой) она будет определена, которая будет сохраняться, пока существует сеанс.

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

Примечание, что существует вероятность того, что в одном сеансе могут быть запущены несколько операторов удаления. Поэтому, прежде чем генерировать исключение, нам нужно установить значение @rows_being_deleted обратно на null.

Следующее будет работать:

DELIMITER //
DROP TRIGGER IF EXISTS prevent_multiple_deletion //
CREATE TRIGGER prevent_multiple_deletion
  BEFORE DELETE ON `test`
  FOR EACH ROW  
    BEGIN

       -- check if the variable is already defined or not
       IF( @rows_being_deleted IS NULL ) THEN 
         SET @rows_being_deleted = 1; -- set its value

       ELSE -- it already exists and we are in next "row"

         -- just for testing to check the row count
         -- SET @rows_being_deleted = @rows_being_deleted + 1;

         -- We have to reset it to null, as within same session
         -- another delete statement may be triggered.
            SET @rows_being_deleted = NULL;

         -- throw exception
         SIGNAL SQLSTATE '45000' 
         SET MESSAGE_TEXT = 'Cannot delete more than one order per time!';
       END IF;

  END //

DELIMITER ;

DB Fiddle Демо 1: Попытка удалить более строки.

DELETE FROM `test` WHERE `id`< 5;

Результат:

Query Error: Error: ER_SIGNAL_EXCEPTION: Cannot delete more than one order per time!


DB Fiddle Демо 2: попытка удалить только одну строку

Запрос №1

DELETE FROM `test` WHERE `id` = 1;

Deletion successfully happened. We can check the remaining rows using Select.

Запрос №2

SELECT * FROM `test`;

| id  | a   | b   |
| --- | --- | --- |
| 2   | 3   | 4   |

Спасибо! statement был опечаткой, но разделитель сводил меня с ума. Пока не вставил перед разделителем.

Gustavo Lessa 03.11.2018 00:33

@GustavoLessa до set signal state, мы можем снова установить значение null. Пожалуйста, проверьте отредактированный ответ.

Madhur Bhaiya 08.11.2018 13:31

Спасибо, Мадхур. Я ответил на ваше решение здесь и начал редактировать ответ, чтобы добавить ту же строку, которую вы добавили сейчас. Ты был быстрее меня =)

Gustavo Lessa 08.11.2018 14:16

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