Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Gatilho MySQL Before Delete para evitar a exclusão de várias linhas


Em primeiro lugar, tirando alguns erros de sintaxe do nosso caminho, da sua tentativa original:
  • Em vez de FOR EACH STATEMENT , deve ser FOR EACH ROW .
  • Como você já definiu o Delimitador para //; você precisa usar // (em vez de ; ) no DROP TRIGGER IF EXISTS .. declaração.
  • Row_Count() terá valor 0 em um Before Delete Trigger , pois nenhuma linha foi atualizada ainda. Portanto, essa abordagem não funcionará.

Agora, o truque aqui é usar Acessível em nível de sessão (e persistente) variáveis ​​definidas pelo usuário . Podemos definir uma variável, digamos @rows_being_deleted , e depois verifique se já está definido ou não.

For Each Row executa o mesmo conjunto de instruções para cada linha sendo excluída . Então, vamos apenas verificar se a variável de sessão já existe ou não. Se não, podemos defini-lo. Então, basicamente, para a primeira linha (sendo excluída), ela será definida, o que persistirá enquanto a sessão estiver lá.

Agora, se houver mais linhas a serem excluídas, o Trigger estaria executando o mesmo conjunto de instruções para as linhas restantes. Na segunda linha, a variável definida anteriormente seria encontrada agora, e podemos simplesmente lançar uma exceção agora.

Observação que há uma chance de que, na mesma sessão, várias instruções de exclusão sejam acionadas. Portanto, antes de lançar uma exceção, precisamos definir o @rows_being_deleted valor de volta para null .

A seguir 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 Demo 1 :Tentando excluir mais de uma linha.
DELETE FROM `test` WHERE `id`< 5;

Resultado:

DB Fiddle Demo 2 :Tentando excluir apenas uma linha

Consulta nº 1
DELETE FROM `test` WHERE `id` = 1;

Consulta nº 2
SELECT * FROM `test`;

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