BEFORE-Trigger zur Validierung
🧪 Ausprobieren – Vorher / Nachher
🌍 Dialekte nebeneinander
Ausgeführt werden nur SQLite (sql.js) und – wo markiert – PostgreSQL (PGlite). MySQL/MariaDB, SQL Server und Oracle sind nach der offiziellen Dokumentation geschrieben, laufen hier aber nicht.
IF NEW.betrag <= 0 THEN RAISE EXCEPTION 'Betrag muss positiv sein' USING ERRCODE = 'check_violation'; END IF; RETURN NEW;
Gibt ein BEFORE-Zeilentrigger NULL zurück, wird die Zeile still übersprungen – eine häufige Fehlerquelle.
DELIMITER // CREATE TRIGGER bestellung_pruefen BEFORE INSERT ON bestellungen FOR EACH ROW BEGIN IF NEW.betrag <= 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Betrag muss positiv sein'; END IF; END// DELIMITER ;
Einfacher und seit MySQL 8.0.16 wirksam: CHECK (betrag > 0) – vorher wurden CHECK-Constraints ignoriert.
CREATE OR ALTER TRIGGER bestellung_pruefen ON bestellungen AFTER INSERT, UPDATE AS BEGIN IF EXISTS (SELECT 1 FROM inserted WHERE betrag <= 0) THROW 50001, 'Betrag muss positiv sein', 1; -- bricht ab, Transaktion wird zurückgerollt END;
Kein BEFORE-Trigger in SQL Server: Prüfung im AFTER- (oder INSTEAD OF-) Trigger, für alle Zeilen von inserted gleichzeitig.
CREATE OR REPLACE TRIGGER bestellung_pruefen BEFORE INSERT OR UPDATE ON bestellungen FOR EACH ROW BEGIN IF :NEW.betrag <= 0 THEN RAISE_APPLICATION_ERROR(-20001, 'Betrag muss positiv sein'); END IF; END; /
CREATE TRIGGER bestellung_pruefen BEFORE INSERT ON bestellungen WHEN new.betrag <= 0 BEGIN SELECT RAISE(ABORT, 'Betrag muss positiv sein'); END;
RAISE(ABORT|FAIL|ROLLBACK, 'Text') bricht ab, RAISE(IGNORE) überspringt die Zeile still.
⚠️ Fallstricke
- Was deklarativ geht, gehört in CHECK, NOT NULL, FOREIGN KEY: schneller, für den Optimierer sichtbar und nicht per Trigger-Reihenfolge umgehbar. Trigger erst, wenn andere Tabellen oder komplexe Regeln beteiligt sind.
- Die Prüfung nur für INSERT anzulegen lässt
UPDATE bestellungen SET betrag = -5durch – immer an UPDATE denken. - Im Beispiel bleibt Bestellung 113 gespeichert, weil jede Anweisung einzeln festgeschrieben wird (Autocommit). In einer Transaktion würde ein ROLLBACK beide verwerfen.
📚 Belege
- SQLite: CREATE TRIGGER – nur FOR EACH ROW, INSTEAD OF nur auf Views, RAISE()
- PostgreSQL: PL/pgSQL – Trigger-Funktionen – NEW/OLD, TG_OP, RETURN NEW/NULL, Audit-Trigger-Beispiel
- MySQL: CREATE TRIGGER – BEFORE/AFTER, nur FOR EACH ROW, FOLLOWS/PRECEDES; REPLACE aktiviert DELETE- und INSERT-Trigger
- MySQL: CHECK Constraints – CHECK wird seit 8.0.16 durchgesetzt
- SQL Server: CREATE TRIGGER (Transact-SQL) – AFTER/INSTEAD OF, anweisungsweise, inserted/deleted, max. 32 Ebenen
- Oracle: CREATE TRIGGER – BEFORE/AFTER, FOR EACH ROW, INSTEAD OF, :NEW/:OLD