Erstens, einige Syntaxfehler aus Ihrem ursprünglichen Versuch aus dem Weg räumen:
- Statt
FOR EACH STATEMENT
, es sollteFOR EACH ROW
sein . - Da Sie das Trennzeichen bereits auf
//
definiert haben; Sie müssen//
verwenden (statt;
) imDROP TRIGGER IF EXISTS ..
Erklärung. Row_Count()
hat den Wert 0 in einemBefore Delete Trigger
, da noch keine Zeilen aktualisiert wurden. Dieser Ansatz wird also nicht funktionieren.
Der Trick besteht nun darin, Zugänglich (und Persistent) auf Sitzungsebene zu verwenden benutzerdefinierte Variablen
. Wir können eine Variable definieren, sagen wir @rows_being_deleted
, und prüfen Sie später, ob es bereits definiert ist oder nicht.
For Each Row
führt denselben Satz von Anweisungen für jede Zeile aus, die gelöscht wird . Wir werden also nur prüfen, ob die Sitzungsvariable bereits vorhanden ist oder nicht. Wenn nicht, können wir es definieren. Im Grunde wird also die erste Zeile (die gelöscht wird) definiert, die bestehen bleibt, solange die Sitzung besteht.
Wenn nun weitere Zeilen gelöscht werden müssen, würde Trigger denselben Satz von Anweisungen für die verbleibenden Zeilen ausführen. In der zweiten Zeile würde nun die vorher definierte Variable stehen und wir können jetzt einfach eine Exception werfen.
Hinweis dass die Möglichkeit besteht, dass innerhalb derselben Sitzung mehrere Löschanweisungen ausgelöst werden. Bevor wir also eine Ausnahme auslösen, müssen wir @rows_being_deleted
festlegen Wert zurück auf null
.
Folgendes wird funktionieren:
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 :Es wird versucht, mehr als eine Zeile zu löschen.
DELETE FROM `test` WHERE `id`< 5;
Ergebnis:
DB Fiddle Demo 2 :Es wird versucht, nur eine Zeile zu löschen
Abfrage 1
DELETE FROM `test` WHERE `id` = 1;
Abfrage 2
SELECT * FROM `test`;
| id | a | b |
| --- | --- | --- |
| 2 | 3 | 4 |