Seite 3 von 3 ErsteErste 123
Ergebnis 21 bis 26 von 26

Thema: Triggerfunktion BEFORE INSERT löst sich nie aus!

  1. #21
    bb1898 ist offline Neuer Benutzer
    Registriert seit
    18.08.2009
    Beiträge
    16

    Standard

    Zitat Zitat von ads Beitrag anzeigen
    Nicht nur du dir, sondern für alle veröffentlichen.

    Mit einigen Details, welche Probleme auftreten können, worauf man achten muss, wie man bestimmte Probleme umgeht oder beseitigt.

    Hier im Forum gibt es eine FAQ Kategorie, dort wäre so etwas gut aufgehoben.
    Ich habe jetzt mal zusammengeschrieben, was mir bis jetzt aufgefallen und so einigermaßen klar geworden ist. Im Wesentlichen also das, was in diesem Thread besprochen wurde. Vielleicht regt es andere zum Weiterschreiben an, ich bin bestimmt noch nicht in sämtliche Fallen getrappt.

    Wenn ich richtig sehe, kann ich selbst nichts in die FAQ-Kategorie schreiben, deshalb mache ich aus dem bisher vorhandenen Text einfach mal einen weiteren Beitrag in diesem Thread und bitte um Verschiebung. Für kritisches Lesen und Korrigieren wäre ich sehr dankbar. Insbesondere mein sehr kurzer Punkt 2 (Ausführen von gespeicherten Funktionen mit Rückgabetyp void) macht mir Kummer: es gelingt mir nicht mehr, auch nur das Wenige dazu in der Dokumentation wiederzufinden, was ich m.E. schon mal gefunden hatte.

    Und was noch ganz fehlt: die Migration einer fertigen Datenbank. Das habe ich schlicht noch nicht ausprobiert. Statt dessen habe ich als erstes eine Datenbank ganz neu aufgebaut, deren Firebird-Version sowieso eine gründliche Umstrukturierung gebraucht hätte.

    Gruß,
    Sibylle
    Geändert von bb1898 (30.08.2009 um 12:44 Uhr) Grund: Letzter Absatz eingefügt.

  2. #22
    bb1898 ist offline Neuer Benutzer
    Registriert seit
    18.08.2009
    Beiträge
    16

    Standard Stolpersteine bei der Migration von Firebird nach PostgreSQL

    1. NOT-NULL-Domain und fehlende Eingabewerte

    Häufige Situation: ein Tabellenfeld braucht einen Eingabewert, der aber bei Bedarf von einem Trigger erzeugt wird (z.B. automatisch erzeugte Primärschlüssel). Das kann praktischer sein als ein Defaultwert, denn wenn im INSERT-Befehl ein Feld nicht weggelassen, sondern mit NULL belegt wird, z.B. von automatisch erzeugten SQL-Befehlen, dann hilft der Defaultwert nichts, der Trigger dagegen schon. Im Fall Firebird kommt noch dazu, dass es den Datentyp "SERIAL" nicht gibt, hier kommt für die Primärschlüssel-Erzeugung nur der Trigger in Frage.

    In Firebird ist es egal, ob für ein solches Feld eine als NOT NULL deklarierte Domain benutzt wird oder NOT NULL in der Spaltendefinition steht: in beiden Fällen wird der Trigger ausgeführt, das Feld wird belegt und der ergänzte Datensatz kommt in die Tabelle.

    Das ist in PostgreSQL anders! Die Trigger-Konstruktion funktioniert hier nur mit einem NOT-NULL-Constraint in der Spaltendefinition, nicht mit einer entsprechend deklarierten Domain. Für Primärschlüssel braucht man keinen Trigger, hier bietet sich SERIAL an, allerdings muss man auch da aufpassen, dass einem kein "hilfreicher" SQL-Builder eine NULL in den INSERT-Befehl schreibt.

    Zeigen kann man das zum Beispiel so:

    Vorbedingung:

    Definition einer NOT-NULL-Domain:
    Code:
    CREATE DOMAIN id_domain INTEGER NOT NULL;
    In der Tabellendefinition wird sie benutzt:
    Code:
    CREATE TABLE numtest(
    idc char(3) primary key,
    nummer id_domain,
    );
    Im "BEFORE INSERT"-Trigger wird die Eingabe für das Feld nummer auf einen legalen Wert gesetzt. In PostgreSQL sieht der Trigger so aus:

    Code:
    CREATE OR REPLACE FUNCTION domain_test() RETURNS trigger AS $$
        BEGIN
            RAISE NOTICE 'nummer (vorher) %', NEW.nummer;
            NEW.nummer = 99;
            RAISE NOTICE 'nummer (nachher) %', NEW.nummer;
            RETURN NEW;
        END;
    $$ LANGUAGE plpgsql;
    
    CREATE TRIGGER domain_test
      BEFORE INSERT
      ON numtest
      FOR EACH ROW
      EXECUTE PROCEDURE domain_test();
    Dass dieser Trigger nicht besonders sinnvoll ist, ist ganz klar, er dient nur der Demonstration.

    Verschiedene Eingaben:

    Legaler Wert:
    Code:
    INSERT INTO numtest (idc. nummer) VALUES ('A00', 5);
    Ausgabe: HINWEIS: nummer (vorher): 5
    HINWEIS: nummer (nachher): 99
    Satz eingefügt, mit nummer = 99.

    Falscher Datentyp:
    Code:
    INSERT INTO numtest (idc, nummer) VALUES ('A01', 'abc');
    Ausgabe: FEHLER: Ungültige Eingabesyntax für ganze Zahl 'abc'
    Satz nicht eingefügt

    Wert fehlt:
    Code:
    INSERT INTO numtest (idc) VALUES ('A02');
    Ausgabe: FEHLER: Domäne id_domain erlaubt keine NULL-Werte

    Wird das Feld nummer nicht mehr mit der Domäne id_domain, sondern als "integer not null" deklariert, gibt es für die Eingaben 5 und 'abc' die gleichen Ausgaben. Ausgabe für den INSERT-Befehl ohne das Feld nummer:

    HINWEIS: nummer (vorher): <NULL>
    HINWEIS: nummer (nachher): 99

    Fazit: ist eine Domain als "NOT NULL" definiert, dann dürfen die Eingaben für entsprechende Felder von vornherein nicht NULL sein. Korrekturversuche in einem "BEFORE INSERT"-Trigger kommen zu spät, dieser Trigger wird gar nicht ausgeführt. Wird der NOT-NULL-Constraint in der Spaltendefinition angegeben, kann ein fehlender Wert im Trigger ergänzt werden.


    Wer das ganze Spielchen mit Firebird nachvollziehen will:

    Firebird hat so etwas wie RAISE NOTICE nicht, aber dieser Trigger eignet sich so einigermaßen:

    Code:
    ALTER TRIGGER BI_NUMTEST ACTIVE
    BEFORE INSERT POSITION 0
    AS 
    BEGIN 
        NEW.remark = 'Vorher: ' || COALESCE(NEW.amount_no2, 'NULL'); 
        NEW.amount_no2 = 99;
        NEW.remark = NEW.remark || ' Nachher: ' || NEW.amount_no2;
    END^
    Die gleichen Eingaben in Firebird: hier macht es keinen Unterschied, ob die Domäne als "NOT NULL" deklariert ist oder die Spalte. Eine Eingabe mit dem falschen Typ ('abc' statt einer Zahl) wird auch hier zurückgewiesen und der Satz nicht eingefügt. Eine fehlende Eingabe wird im Trigger ergänzt und der Satz wird mit diesem Wert eingefügt.


    2. Ausführen von Funktionen

    Den Unterschied zwischen ausführbaren und selektierbaren Prozeduren, der in Firebird wichtig ist, kennt PostgreSQL nicht. Es gibt (abgesehen von Triggerprozeduren) nur Funktionen, die als Rückgabetyp void haben können - das entspricht am ehesten der ausführbaren Prozedur von Firebird. Aufgerufen werden alle Funktionen mit SELECT, eine Funktion mit Rückgabetyp void kann mit "SELECT meinefunktion(parameterliste)" oder auch mit "SELECT * FROM meinefunktion(parameterliste)" aufgerufen werden. In der Dokumentation sind solche Funktionen stiefmütterlich behandelt (oder nur schwer zu finden?).

  3. #23
    ads
    ads ist offline Super-Moderator
    Registriert seit
    08.02.2006
    Ort
    MD
    Beiträge
    4.020

    Standard

    Danke schön.

    Ich habe aus deinem Posting mal einen FAQ-Beitrag erstellt:
    http://www.pg-forum.de/h-ufig-gestel...ostgresql.html

    Allerdings habe ich den letzten Satz entfernt und statt dessen die dafür passende Dokumentation verlinkt. Auf der dort angegebenen Seite sind all die angesprochenen Punkte imho gut und mit Beispielen erklärt.
    Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören

    Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

    PostgreSQL Service & Support

  4. #24
    bb1898 ist offline Neuer Benutzer
    Registriert seit
    18.08.2009
    Beiträge
    16

    Standard

    Zitat Zitat von ads Beitrag anzeigen
    Danke schön.

    Ich habe aus deinem Posting mal einen FAQ-Beitrag erstellt:
    http://www.pg-forum.de/h-ufig-gestel...ostgresql.html

    Allerdings habe ich den letzten Satz entfernt und statt dessen die dafür passende Dokumentation verlinkt. Auf der dort angegebenen Seite sind all die angesprochenen Punkte imho gut und mit Beispielen erklärt.
    Danke. Das war genau die Stelle; das void-Beispiel fehlt in der deutschsprachigen Version. Es ist wahrscheinlich generell ratsam, das englische Original zu benutzen, richtig?

  5. #25
    ads
    ads ist offline Super-Moderator
    Registriert seit
    08.02.2006
    Ort
    MD
    Beiträge
    4.020

    Standard

    Zitat Zitat von bb1898 Beitrag anzeigen
    Danke. Das war genau die Stelle; das void-Beispiel fehlt in der deutschsprachigen Version.
    Welche URL hattest du da verwendet?


    Es ist wahrscheinlich generell ratsam, das englische Original zu benutzen, richtig?
    Ja, die englischsprachige ist aktuell.
    In dem Link in meiner Signatur ist das allerdings auch richtig enthalten ;-)
    Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören

    Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

    PostgreSQL Service & Support

  6. #26
    bb1898 ist offline Neuer Benutzer
    Registriert seit
    18.08.2009
    Beiträge
    16

    Standard

    Zitat Zitat von ads Beitrag anzeigen
    Welche URL hattest du da verwendet?
    Diesen hier, von der deutschen PostgreSQL-Seite (www.postgresql.de):
    PostgreSQL: Das offizielle Handbuch

    Ja, die englischsprachige ist aktuell.
    In dem Link in meiner Signatur ist das allerdings auch richtig enthalten ;-)
    Das ist nicht das Problem, ich hab' die Originaldokumentation schon gefunden, sonst hätte ich den ganzen Umstieg gar nicht erst angefangen. Deshalb war ich mir ja auch sicher, dass ich die Information schon mal gesehen hatte und nur nicht wiederfinden konnte. Bloß zum Zitieren in einem deutschen Text hätte ja eine deutschsprachige Dokumentation schon einen gewissen Vorteil.

    Das ist aber wohl immer dasselbe, richtig aktuell sind die übersetzten Handbücher nie.

    Dank und Gruß,
    Sibylle

Seite 3 von 3 ErsteErste 123

Stichworte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Links: Tobias Bauer - IT- und Funkdienstleistungen   -   Bilderrahmen-kaufen.de - Der Onlineshop für Bilderrahmen & Fotorahmen   -   Funkforum