Po pierwsze, usunięcie błędów składniowych z naszej pierwotnej próby:
- Zamiast
FOR EACH STATEMENT
, powinno byćFOR EACH ROW
. - Ponieważ już zdefiniowałeś separator jako
//
; musisz użyć//
(zamiast;
) wDROP TRIGGER IF EXISTS ..
oświadczenie. Row_Count()
będzie miał wartość 0 wBefore Delete Trigger
, ponieważ żadne wiersze nie zostały jeszcze zaktualizowane. Więc to podejście nie zadziała.
Teraz sztuczka polega na tym, aby użyć Dostępnych (i trwałych) na poziomie sesji zmienne zdefiniowane przez użytkownika
. Możemy zdefiniować zmienną, powiedzmy @rows_being_deleted
, a później sprawdź, czy jest już zdefiniowany, czy nie.
For Each Row
uruchamia ten sam zestaw instrukcji dla każdego usuniętego wiersza . Więc po prostu sprawdzimy, czy zmienna sesji już istnieje, czy nie. Jeśli tak nie jest, możemy to zdefiniować. Zasadniczo więc dla pierwszego wiersza (usuwanego) zostanie on zdefiniowany, co będzie trwać tak długo, jak długo będzie trwała sesja.
Teraz, jeśli jest więcej wierszy do usunięcia, Trigger uruchomi ten sam zestaw instrukcji dla pozostałych wierszy. W drugim wierszu zostałaby teraz znaleziona wcześniej zdefiniowana zmienna i możemy teraz po prostu rzucić wyjątek.
Uwaga że istnieje szansa, że w ramach tej samej sesji może zostać uruchomionych wiele instrukcji usuwania. Dlatego przed zgłoszeniem wyjątku musimy ustawić @rows_being_deleted
wartość z powrotem do null
.
Działają następujące:
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 :Próbuję usunąć więcej niż wiersz.
DELETE FROM `test` WHERE `id`< 5;
Wynik:
DB Fiddle Demo 2 :Próba usunięcia tylko jednego wiersza
Zapytanie nr 1
DELETE FROM `test` WHERE `id` = 1;
Zapytanie nr 2
SELECT * FROM `test`;
| id | a | b |
| --- | --- | --- |
| 2 | 3 | 4 |