Kapitel 20. Trigger

Inhaltsverzeichnis

20.1. CREATE TRIGGER
20.2. DROP TRIGGER
20.3. Verwendung von Triggern

Ein Trigger ist ein benanntes Datenbankobjekt, das mit einer Tabelle verbunden ist und aktiviert wird, wenn für diese Tabelle ein bestimmtes Ereignis eintritt. So legen beispielsweise die folgenden Anweisungen eine Tabelle und einen INSERT-Trigger an. Der Trigger addiert die Werte, die in eine der Tabellenspalten geladen werden:

mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
Query OK, 0 rows affected (0.03 sec)

mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;
Query OK, 0 rows affected (0.06 sec)

Dieses Kapitel beschreibt die Syntax, mit der Trigger angelegt und gelöscht werden, und zeigt einige Anwendungsbeispiele für sie. Über die Beschränkungen für Trigger finden Sie in Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“, genauere Hinweise. Informationen über Binärlogging in Bezug auf Trigger finden Sie unter Abschnitt 19.4, „Binärloggen gespeicherter Routinen und Trigger“.

20.1. CREATE TRIGGER

CREATE
    [DEFINER = { user | CURRENT_USER }]
    TRIGGER trigger_name trigger_time trigger_event
    ON tbl_name FOR EACH ROW trigger_stmt

Diese Anweisung erzeugt einen neuen Trigger. Ein Trigger ist ein benanntes Datenbankobjekt, das mit einer Tabelle verbunden ist und aktiviert wird, wenn für diese Tabelle ein bestimmtes Ereignis eintritt. Gegenwärtig ist zur Ausführung von CREATE TRIGGER das TRIGGER-Recht für die Tabelle erforderlich, zu welcher der Trigger gehört. (Vor MySQL 5.1.6 war für diese Anweisung das SUPER-Recht notwendig.)

Der Trigger wird mit der Tabelle tbl_name verbunden, die eine permanante Tabelle sein muss. Mit einer als TEMPORARY definierten Tabelle oder View lässt sich kein Trigger verbinden.

Wenn der Trigger aktiviert wird, legt die DEFINER-Klausel fest, welche Rechte angewendet werden. Genaueres erfahren Sie weiter unten in diesem Kapitel.

Die trigger_time ist der Zeitpunkt der Trigger-Aktion. Sie kann BEFORE oder AFTER sein, je nachdem, ob der Trigger sich vor oder nach der Anweisung einschaltet, die ihn aktivierte.

Das trigger_event gibt an, welche Art von Anweisung den Trigger aktiviert. Das trigger_event kann eines der folgenden Ereignisse sein:

  • INSERT: Der Trigger wird immer dann aktiviert, wenn eine neue Zeile in die Tabelle eingefügt wird, beispielsweise mit INSERT-, LOAD DATA- und REPLACE-Anweisungen.

  • UPDATE: Der Trigger wird immer dann aktiviert, wenn eine Zeile in der Tabelle geändert wird, beispielsweise mit UPDATE-Anweisungen.

  • DELETE: Der Trigger wird immer dann aktiviert, wenn eine Zeile aus der Tabelle gelöscht wird, beispielsweise mit DELETE- und REPLACE-Anweisungen.

Es ist wichtig, zu verstehen, dass das trigger_event weniger eine Art von SQL-Anweisung ist, die den Trigger aktiviert, als vielmehr eine Art von Tabellenoperation. So wird beispielsweise ein INSERT-Trigger nicht nur von INSERT-Anweisungen, sondern auch von LOAD DATA-Anweisungen aktiviert, weil beide Anweisungen Zeilen in eine Tabelle einfügen.

Ein potenziell verwirrendes Beispiel dafür ist die Syntax von INSERT INTO ... ON DUPLICATE KEY UPDATE ...: Für jede Zeile wird ein BEFORE INSERT-Trigger aktiviert, gefolgt entweder von einem AFTER INSERT-Trigger oder von dem Triggerpaar aus BEFORE UPDATE und AFTER UPDATE, je nachdem, ob ein doppelter Schlüssel für die Zeile vorlag oder nicht.

Es dürfen keine zwei Trigger einer Tabelle dieselbe Aktionszeit und dasselbe Trigger-Ereignis haben. Zum Beispiel können Sie keine zwei BEFORE UPDATE-Trigger für eine Tabelle definieren. Sie können jedoch einen BEFORE UPDATE- und einen BEFORE INSERT-Trigger oder einen BEFORE UPDATE- und einen AFTER UPDATE-Trigger definieren.

trigger_stmt ist die Anweisung, die ausgeführt wird, wenn der Trigger in Aktion tritt. Wenn Sie mehrere Anweisungen ausführen möchten, verwenden Sie das Konstrukt BEGIN ... END für zusammengesetzte Anweisungen. So können Sie auch dieselben Anweisungen wie in gespeicherten Routinen verwenden. Siehe auch Abschnitt 19.2.5, „BEGIN ... END-Syntax für komplexe Anweisungen“.

Hinweis: Zurzeit werden Trigger nicht von kaskadierenden Fremdschlüsselaktionen aktiviert. Dieser Mangel wird jedoch so bald wie möglich behoben.

In MySQL 5.1 können Sie Trigger schreiben, die Direktverweise auf Tabellennamen enthalten, wie der Trigger testref im folgenden Beispiel:

CREATE TABLE test1(a1 INT);
CREATE TABLE test2(a2 INT);
CREATE TABLE test3(a3 INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE test4(
  a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  b4 INT DEFAULT 0
);

DELIMITER |

CREATE TRIGGER testref BEFORE INSERT ON test1
  FOR EACH ROW BEGIN
    INSERT INTO test2 SET a2 = NEW.a1;
    DELETE FROM test3 WHERE a3 = NEW.a1;  
    UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
  END;
|

DELIMITER ;

INSERT INTO test3 (a3) VALUES 
  (NULL), (NULL), (NULL), (NULL), (NULL), 
  (NULL), (NULL), (NULL), (NULL), (NULL);

INSERT INTO test4 (a4) VALUES 
  (0), (0), (0), (0), (0), (0), (0), (0), (0), (0);

Angenommen, Sie setzen die folgenden Werte in die Tabelle test1 ein, wie hier gezeigt:

mysql> INSERT INTO test1 VALUES 
    -> (1), (3), (1), (7), (1), (8), (4), (4);
Query OK, 8 rows affected (0.01 sec)
Records: 8  Duplicates: 0  Warnings: 0

Die Daten in den vier Tabellen stellen sich dann folgendermaßen dar:

mysql> SELECT * FROM test1;
+------+
| a1   |
+------+
|    1 |
|    3 |
|    1 |
|    7 |
|    1 |
|    8 |
|    4 |
|    4 |
+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM test2;
+------+
| a2   |
+------+
|    1 |
|    3 |
|    1 |
|    7 |
|    1 |
|    8 |
|    4 |
|    4 |
+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM test3;
+----+
| a3 |
+----+
|  2 |
|  5 |
|  6 |
|  9 |
| 10 |
+----+
5 rows in set (0.00 sec)

mysql> SELECT * FROM test4;
+----+------+
| a4 | b4   |
+----+------+
|  1 |    3 |
|  2 |    0 |
|  3 |    1 |
|  4 |    2 |
|  5 |    0 |
|  6 |    0 |
|  7 |    1 |
|  8 |    1 |
|  9 |    0 |
| 10 |    0 |
+----+------+
10 rows in set (0.00 sec)

Die Spalten der Subjekttabelle (der Tabelle, zu welcher der Trigger gehört) können Sie mit den Aliasnamen OLD und NEW ansprechen. OLD.col_name bezieht sich auf eine Spalte mit einer vorhandenen Zeile, bevor diese geändert oder gelöscht wurde, und NEW.col_name auf die Spalte mit einer neu eingefügten oder geänderten Zeile.

Die DEFINER-Klausel gibt an, welches MySQL-Konto zur Prüfung der Zugriffsberechtigungen bei Aktivierung des Triggers herangezogen wird. Wenn ein user-Wert angegeben ist, dann als MySQL-Konto im Format 'user_name'@'host_name' (dasselbe Format wird auch in der GRANT-Anweisung verwendet). Die Werte user_name und host_name sind beide obligatorisch. CURRENT_USER kann auch als CURRENT_USER() angegeben werden. Der Standardwert für DEFINER ist der Benutzer, der die CREATE TRIGGER-Anweisung ausführt. (Dies ist dasselbe wie DEFINER = CURRENT_USER.)

Wenn Sie die DEFINER-Klausel angeben, dürfen Sie den Wert auf kein anderes als Ihr eigenes Konto einstellen, wenn Sie nicht über das SUPER-Recht verfügen. Die zulässigen Werte für den DEFINER-Benutzer richten sich nach folgenden Regeln:

  • Wenn Sie nicht das SUPER-Recht haben, ist der einzig zulässige user-Wert Ihr eigenes Konto, das entweder buchstäblich oder über CURRENT_USER angegeben werden kann. Auf ein anderes Konto können Sie den DEFINER nicht einstellen.

  • Wenn Sie das SUPER-Recht haben, können Sie jeden gültigen Kontonamen angeben, der syntaktisch zulässig ist. Existiert das Konto in Wirklichkeit nicht, wird eine Warnung ausgegeben.

Hinweis: In älteren Versionen als MySQL 5.1.6 wird das SUPER-Recht für die Benutzung von CREATE TRIGGER verlangt, sodass für diese älteren Releases nur die zweite der oben genannten Regeln gilt. Seit der Version 5.1.6 ist SUPER nur noch erforderlich, wenn der DEFINER auf etwas anderes als das eigene Konto eingestellt werden soll.

MySQL prüft Trigger-Berechtigungen folgendermaßen:

  • Zur CREATE TRIGGER-Zeit muss der Benutzer, der die Anweisung gibt, das TRIGGER-Recht besitzen. (Vor MySQL 5.1.6 war sogar das SUPER-Recht erforderlich.)

  • Zum Zeitpunkt der Trigger-Aktivierung werden die Berechtigungen mit denen des DEFINER-Benutzers verglichen. Dieser benötigt folgende Berechtigungen:

    • Das TRIGGER-Recht (vor MySQL 5.1.6 das SUPER-Recht).

    • Das SELECT-Recht für die Subjekttabelle, wenn mit OLD.col_name oder NEW.col_name in der Trigger-Definition auf Tabellenspalten verwiesen wird.

    • Das UPDATE-Recht für die Subjekttabelle, wenn ihre Spalten Ziel von SET NEW.col_name = value-Zuweisungen in der Trigger-Definition sind.

    • Zusätzlich alle anderen Rechte, die normalerweise für die vom Trigger ausgeführten Anweisungen erforderlich sind.

20.2. DROP TRIGGER

DROP TRIGGER [schema_name.]trigger_name

Diese Anweisung löscht einen Trigger. Der Schemaname (Datenbank) ist optional. Wird kein Schema angegeben, wird der Trigger aus dem Standardschema gelöscht. DROP TRIGGER wurde in MySQL 5.0.2 hinzugefügt und erfordert das TRIGGER-Recht für die Tabelle, zu welcher der Trigger gehört. (Vor MySQL 5.1.6 war für diese Anweisung das SUPER-Recht erforderlich.)

Hinweis: Wenn Sie von einer älteren MySQL-Version als MySQL 5.0.10 auf 5.0.10 oder neuer aufrüsten (einschließlich aller MySQL 5.1-Releases), müssen Sie alle Trigger vor dem Upgrade löschen und danach wieder neu erstellen. DROP TRIGGER funktioniert nach dem Upgrade nicht mehr. Unter Abschnitt 2.10.1, „Upgrade von MySQL 5.0“, wird eine empfehlenswerte Upgrade-Prozedur beschrieben.

20.3. Verwendung von Triggern

Dieser Abschnitt beschreibt die Verwendung von Triggern in MySQL 5.1 sowie einige Einschränkungen für die Nutzung von Triggern. Weitere Beschränkungen im Zusammenhang mit Triggern sind in Abschnitt I.1, „Beschränkungen bei gespeicherten Routinen und Triggern“, geschildert.

Ein Trigger ist ein benanntes Datenbankobjekt, das mit einer Tabelle verbunden ist und aktiviert wird, wenn für diese Tabelle ein bestimmtes Ereignis eintritt. Trigger werden beispielsweise verwendet, um Werte zu überprüfen, die in eine Tabelle eingesetzt werden sollen, oder um Berechnungen mit Werten auszuführen, die zu einem Update gehören.

Ein Trigger ist mit einer Tabelle verbunden und wird aktiviert, wenn eine INSERT-, DELETE- oder UPDATE-Anweisung für diese Tabelle ausgeführt wird. Ein Trigger kann so eingestellt werden, dass er entweder vor oder nach der auslösenden Anweisung aktiviert wird. So können Sie beispielsweise veranlassen, dass ein Trigger jeweils vor jeder Zeilenlöschung oder nach jeder Zeilenänderung aktiviert wird.

Ein Trigger wird mit CREATE TRIGGER erstellt und mit DROP TRIGGER gelöscht. Die Syntax dieser Anweisungen wird unter Abschnitt 20.1, „CREATE TRIGGER, und Abschnitt 20.2, „DROP TRIGGER, erklärt.

Das folgende einfache Beispiel verbindet einen Trigger mit einer Tabelle für den Fall von INSERT-Anweisungen. Er fungiert als Sammelbecken, um die Werte zu addieren, die in eine der Tabellenspalten eingefügt werden.

Die folgenden Anweisungen legen eine Tabelle und einen Trigger für sie an:

mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;

Die CREATE TRIGGER-Anweisung erzeugt einen Trigger namens ins_sum, der mit der account-Tabelle verbunden ist. Außerdem enthält sie Klauseln, um die Aktivierungszeit des Triggers, das Trigger-Ereignis und die eigentlichen Trigger-Aktionen festzulegen:

  • Das Schlüsselwort BEFORE zeigt die Aktivierungszeit des Triggers an. Hier sollte der Trigger in Aktion treten, bevor eine Zeile in die Tabelle eingefügt wird. Das zweite hier zulässige Schlüsselwort ist AFTER.

  • Das Schlüsselwort INSERT zeigt das Ereignis an, welches den Trigger aktiviert. In unserem Beispiel lassen INSERT-Anweisungen den Trigger aktiv werden. Sie können jedoch auch Trigger für DELETE- und UPDATE-Anweisungen anlegen.

  • Hinter dem FOR EACH ROW steht, welche Anweisung jedes Mal ausgeführt werden soll, wenn der Trigger in Aktion tritt, was in diesem Fall für jede von der auslösenden Anweisung betroffene Zeile einmal passiert. Die Trigger-Anweisung in diesem Beispiel ist ein einfaches SET, das die Werte, die in die amount-Spalte eingefügt werden, sammelt. Die Anweisung nennt die Spalte NEW.amount und meint damit „den Wert, der in die neue Zeile der Spalte amount eingesetzt werden soll“.

Um den Trigger verwenden zu können, setzen Sie die Variable, welche die Werte sammelt, auf null, führen eine INSERT-Anweisung aus und schauen, welchen Wert die Variable danach hat:

mysql> SET @sum = 0;
mysql> INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
mysql> SELECT @sum AS 'Total amount inserted';
+-----------------------+
| Total amount inserted |
+-----------------------+
| 1852.48               |
+-----------------------+

In diesem Fall hat @sum nach Ausführung der INSERT-Anweisung den Wert 14.98 + 1937.50 - 100, also 1852.48.

Gelöscht wird der Trigger mit der DROP TRIGGER-Anweisung. Wenn der Trigger nicht im Standardschema definiert ist, müssen Sie außerdem den Schemanamen dazusetzen:

mysql> DROP TRIGGER test.ins_sum;

Da Trigger-Namen im Schema-Namensraum liegen, müssen alle Trigger innerhalb eines Schemas eindeutige Namen haben. Trigger in unterschiedlichen Schemata können dagegen gleich heißen.

Zusätzlich zu dem Erfordernis, dass Trigger-Namen in einem Schema eindeutig sein müssen, gibt es noch weitere Einschränkungen betreffend die Typen der Trigger. Insbesondere dürfen keine zwei Trigger einer Tabelle dieselbe Aktivierungszeit und dasselbe Aktivierungsereignis haben. Sie können also nicht zwei BEFORE INSERT-Trigger oder zwei AFTER UPDATE-Trigger für dieselbe Tabelle definieren. Normalerweise dürfte diese Beschränkung jedoch keine Rolle spielen, da ein Trigger auch so definiert werden kann, dass er mehrere Anweisungen in einem BEGIN ... END-Block als zusammengesetzte Anweisung hinter dem FOR EACH ROW ausführt. (Weiter unten in diesem Abschnitt finden Sie ein Beispiel dazu.)

Mit den Schlüsselwörtern OLD und NEW können Sie auf Spalten zugreifen, die von einem Trigger betroffen sind. (Die Groß- und Kleinschreibung spielt für OLD und NEW keine Rolle.) In einem INSERT-Trigger kann nur NEW.col_name benutzt werden, da keine alte Zeile vorhanden ist, und in einem DELETE-Trigger nur OLD.col_name, da keine neue Zeile vorhanden ist. In einem UPDATE-Trigger können sowohl OLD.col_name für den Verweis auf Tabellenzeilen vor der Änderung als auch NEW.col_name für einen Verweis auf die geänderten Zeilen verwendet werden.

Ein Spaltenname mit OLD ist schreibgeschützt. Sie können ihn benutzen (sofern Sie das SELECT-Recht für ihn haben), aber nicht ändern. Ein Spaltenname mit NEW kann mit dem entsprechenden SELECT-Recht angesprochen werden. In einem BEFORE-Trigger können Sie auch seinen Wert mit SET NEW.col_name = value ändern, sofern Sie das UPDATE-Recht dafür haben. Dies bedeutet, dass Sie einen Trigger einsetzen können, um die Werte zu ändern, die in eine neue Zeile eingefügt oder mit denen eine Zeile aktualisiert wird.

In einem BEFORE-Trigger ist der NEW-Wert für eine AUTO_INCREMENT-Spalte 0 und nicht die automatisch generierte laufende Nummer, die angelegt wird, wenn der neue Datensatz tatsächlich eingefügt wird.

OLD und NEW sind MySQL-Erweiterungen für Trigger.

Mit dem BEGIN ... END-Konstrukt können Sie einen Trigger definieren, der mehrere Anweisungen ausführt. Innerhalb des BEGIN-Blocks können Sie auch eine andere für gespeicherte Routinen zulässige Syntax verwenden, wie beispielsweise Bedingungsanweisungen und Schleifen. Doch wie für gespeicherte Routinen gilt auch für Trigger: Wenn Sie das mysql-Programm verwenden, um einen Trigger für mehrere Anweisungen zu definieren, muss das Trennzeichen für die mysql-Anweisung auf etwas anderes eingestellt werden, damit das Begrenzungszeichen ; für Anweisungen in der Trigger-Definition zur Verfügung steht. Dies wird im folgenden Beispiel deutlich, in dem ein UPDATE-Trigger definiert wird, der für jede Zeilenänderung den neuen Wert prüft und diesen so modifiziert, dass er im Bereich zwischen 0 und 100 liegt. Dieser Trigger muss ein BEFORE-Trigger sein, da der Wert überprüft werden muss, bevor er in die Zeile eingesetzt wird:

mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
    -> FOR EACH ROW
    -> BEGIN
    ->     IF NEW.amount < 0 THEN
    ->         SET NEW.amount = 0;
    ->     ELSEIF NEW.amount > 100 THEN
    ->         SET NEW.amount = 100;
    ->     END IF;
    -> END;//
mysql> delimiter ;

Unter Umständen ist es einfacher, eine gespeicherte Prozedur separat zu definieren und dann im Trigger mit einer einfachen CALL-Anweisung aufzurufen. Dies ist auch dann von Vorteil, wenn Sie dieselbe Routine in mehreren Triggern aufrufen möchten.

In Anweisungen, die ein aktivierter Trigger ausführt, ist nicht alles erlaubt:

  • Der Trigger darf nicht mit einer CALL-Anweisung gespeicherte Prozeduren aufrufen, die Daten an den Client zurückgeben oder dynamisches SQL nutzen. (Gespeicherte Prozeduren dürfen jedoch an den Trigger Daten über OUT- oder INOUT-Parameter zurückgeben.)

  • Der Trigger darf keine Anweisungen benutzen, die explizit oder implizit eine Transaktion starten oder beenden, wie etwa START TRANSACTION, COMMIT oder ROLLBACK.

Mit Fehlern bei der Ausführung eines Triggers geht MySQL folgendermaßen um:

  • Bei einem Fehler in einem BEFORE-Trigger wird die Operation auf der betreffenden Zeile nicht ausgeführt.

  • Ein AFTER-Trigger wird nur ausgeführt, wenn der BEFORE-Trigger (wenn vorhanden) und die Zeilenoperation beide erfolgreich waren.

  • Ein Fehler während eines BEFORE- oder AFTER-Triggers lässt die gesamte Anweisung scheitern, durch die der Trigger aufgerufen wurde.

  • Wenn auf einer Transaktionstabelle ein Trigger (und mit ihm die gesamte Anweisung) scheitert, müssen alle durch diese Anweisung verursachten Änderungen zurückgerollt werden. Da ein solcher Rollback bei Tabellen, die nicht an einer Transaktion beteiligt sind, unmöglich ist, bleiben dort alle bis zu dem Fehler eingetretenen Änderungen wirksam, obwohl die Anweisung eigentlich gescheitert ist.


Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.