Rolf B: mysql trigger

Beitrag lesen

Hallo der henry,

ich möchte das erste mal einen tripper in einer mysql Datenbank bzw. Tabelle anwenden.

🤣

Ich möchte einen Trigger in der Tabelle "datenpunktliste" bei Eingabe bzw. update (Änderung) auslösen. Dann soll der Wert aus dem Feld "datenpunktliste.spsname" in das Feld "datenpunktliste.spsvarname" geschrieben werden.

D.h. spsvarname ist ein synthetischer Wert, der sich aus spsname, varname und dem Datum der letzten Änderung zusammensetzt?

Aus DB-Modellierungssicht ist dazu zu sagen: Pfui. Mach ein drittes Feld spsvardate oder so, schreibe das Änderungsdatum hinein und setze den Wert von spsvarname bei Bedarf in der SQL Query oder in den Anwendung zusammen.

Um das Änderungsdatum automatisch hinzubekommen, kannst Du für spsvardate einen Defaultvalue festlegen.

create table datenpunktliste
   ...
   spsvardate DATE NOT NULL DEFAULT CURDATE()
   ...

Damit ist die Vorbelegung beim INSERT erledigt. Nun stellt sich die Frage, was bei Updates von istwert oder datentyp ist. Soll sich das Datum dann auch ändern? Oder nur bei Updates auf spsname und varname? Wenn jeglicher Update das Datum ändern darf, kannst Du das der Default-Definition hinzufügen - musst dann aber auf DATETIME wechseln:

   spsvardate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP()

D.h. du musst dann bei jedem Zugriff auf spsvardate mit der DATE()-Funktion den Zeitanteil aus spsvardate ausmaskieren.

Wenn nur Updates auf spsname und varname das Datum ändern sollen, kannst Du beim Date-Typ bleiben, brauchst aber einen Update-Trigger. Darin verwendest Du die Pseudo-Aliase OLD und NEW, um den Wert der Felder vor und nach dem Update zu vergleichen:

DELIMITER $$

CREATE TRIGGER `trigg_create_spsvarname`
   AFTER UPDATE ON `datenpunktliste`
   FOR EACH ROW
   BEGIN
      IF (OLD.spsname <> NEW.spsname) OR (OLD.varname <> NEW.varname) THEN
         SET NEW.spsvardate = CURDATE();
      END IF;
   END$$

DELIMITER ;

Die Akrobatik mit dem Delimiter ist nötig, weil andernfalls die Semikolons in der Trigger-Definition den Create-Befehl zu früh beenden.

Beachte: Wenn spsname oder varname eine Collation verwenden, die auf _ci endet (case insensitive) enthält, dann löst das Ändern des Inhaltes von - sagen wir mal - "FOO" zu "Foo" den Trigger NICHT aus. Dafür benötigt die Column eine _bin Collation (utf8_general_cs gibt's nicht?!?!).

Wenn Du das Zusammensetzen von spsname, spsvardate und varname in den Queries nicht hinschreiben willst, dann füge der Table eine GENERATED VIRTUAL COLUMN hinzu.

create table datenpunktliste
   ...
   spsvarname VARCHAR(99) AS CONCAT(spsname,spsvardate ,varname)
   ...

spsvardate konvertiert sich automatisch in JJJJ-MM-TT. Es sei denn, es ist ein Datetime-Datentyp, dann musst Du DATE(spsvardate) verwenden. Als Länge im varchar gib die Summe der Längen von spsname und varname plus 10 (für das Datum) an.

Den synthetisierten Wert per Trigger in die Table schreiben: Nein, nicht tun. Nur unter Androhung von sadistischer Folter. Wenn es um Performance beim Zugriff geht: mach eine materialisierte Spalte draus. Die belegt dann zwar Speicher, aber dafür kann man auch einen Index drauflegen.

create table datenpunktliste
   ...
   spsvarname VARCHAR(...) AS CONCAT(spsname,spsvardate,varname) STORED
   ...

Soweit ich weiß, funktioniert das alles in MYSQL und MariaDB. Nur das Einbringen von ALTER auf die Tabellen mit HeidiSQL war ein Drama, das generierte mir bei generierten Spalten einen SQL Syntaxfehler nach dem anderen...

Rolf

--
sumpsi - posui - obstruxi