sql >> Base de Datos >  >> RDS >> Mysql

Desencadenador MySQL Before Delete para evitar eliminar varias filas

En primer lugar, eliminar algunos errores de sintaxis de su intento original:

  • En lugar de FOR EACH STATEMENT , debería ser FOR EACH ROW .
  • Dado que ya ha definido el Delimitador para //; necesitas usar // (en lugar de ; ) en el DROP TRIGGER IF EXISTS .. declaración.
  • Row_Count() tendrá valor 0 en un Before Delete Trigger , ya que aún no se han actualizado filas. Entonces este enfoque no funcionará.

Ahora, el truco aquí es usar accesible (y persistente) a nivel de sesión variables definidas por el usuario . Podemos definir una variable, digamos @rows_being_deleted , y luego verifique si ya está definido o no.

For Each Row ejecuta el mismo conjunto de declaraciones para cada fila que se elimina . Entonces, solo verificaremos si la variable de sesión ya existe o no. Si no es así, podemos definirlo. Básicamente, para la primera fila (que se elimina), se definirá, lo que persistirá mientras la sesión esté allí.

Ahora, si hay más filas para eliminar, Trigger ejecutaría el mismo conjunto de declaraciones para las filas restantes. En la segunda fila, la variable previamente definida se encontraría ahora, y ahora simplemente podemos lanzar una excepción.

Nota que existe la posibilidad de que, dentro de la misma sesión, se activen varias declaraciones de eliminación. Entonces, antes de lanzar una excepción, debemos configurar @rows_being_deleted valor de nuevo a null .

Lo siguiente funcionará:

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 Demostración 1 :Intentando eliminar más de una fila.

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

Resultado:

DB Fiddle Demostración 2 :Tratando de eliminar solo una fila

Consulta #1

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

Consulta #2

SELECT * FROM `test`;

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