| Autor |
Beitrag |
matze
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: Mo 11.12.06 22:05
Hallo
Ich habe ein Problem mit einem Trigger in Firebird.
Ich habe eine Tabelle mit den folgenden Feldern:
RBCard, Anrede, V_Name, N_Name usw. und last_seen. Was mein Trigger jetzt machen soll, ist immer wenn ein Feld ausser dem last_seen in eimem Query gesetzt wird, das last_changed auf einen aktuellen zeitpunkt zu setzten.
Also konkret:
wenn ich UPDATE "USER" SET anrede = 'frau' ausführe soll last_changed auf jetzt gesetzt werden. Wenn ich aber UPDATE "USER" SET last_changed = current_timestamp ausführe soll last_changed nicht gesetzt werden.
Mein bisheriger Trigger sieht so aus. Aber er funktioniert nicht. Es wird IMMER last_changed gesetzt !
SQL-Anweisung 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| CREATE TRIGGER USER_BU0 FOR "USER" ACTIVE BEFORE UPDATE POSITION 0 AS begin if ((new.rbcard is not NULL) or (new.anrede is not NULL) or (new.v_name is not NULL) or (new.n_name is not NULL) or (new.telefon is not NULL) or (new.handy is not NULL) or (new.email is not NULL) or (new.comment is not NULL) or (new.bonus is not NULL)) then new.last_changed = current_timestamp; end |
Was mache ich falsch ?
_________________ In the beginning was the word.
And the word was content-type: text/plain.
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Mo 11.12.06 22:26
Ich würde old. mit new. vergleichen.
_________________ Markus Kinzler.
|
|
hansa
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Di 12.12.06 04:44
matze hat folgendes geschrieben: | | UPDATE "USER" SET anrede = 'frau' ausführe soll last_changed auf jetzt gesetzt werden. |
Dann muss doch nur im Trigger folgendes stehen :
SQL-Anweisung 1: 2:
| IF anrede = 'frau' THEN SET last_changed = current_timestamp; |
Egal was drumrum passiert. Auf Current_timestamp mit '=' zu prüfen, das wäre mir zu riskant. Was, wenn während solcher Aktionen die Sekunde umspringt ? Wird nicht sogar mit Millisekunden gerechnet ? Es gibt ja auch noch 'now'. Der Unterschied ist folgender : now hat die momentane Rechnerzeit und current_timestamp die Zeit zu Beginn der Anweisung.  Wem hilft sowas jetzt ?
Das nächste : wieso Abfrage auf 'frau' ? Was wäre, wenn es eine 'Frau' ist ? So was gehört in einen Zahlentyp. Zumindest, wenn es nicht von Hand eingegeben werden muss.
Zu guter Letzt noch das Wichtigste : Du verwendest einen Before-Update-Trigger. Der dient eigentlich hauptsächlich zum vorbesetzen von Werten. Z.B., um NULLs direkt auszuschalten, oder eben 'frau' vorzugeben. Vielleicht ist das sogar der eigentliche Fehler. Muß auf das Editieren der Datensätze reagiert werden, worauf last_changed ja hindeutet, dann muss es ein AFTER UPDATE Trigger sein.
_________________ Gruß
Hansa
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Di 12.12.06 06:24
@hansa: Das mit 'Frau' war nur ein Beispiel. Ein before-Trigger ist hier passend, da er ja Werte der Tabelle ändern will.
_________________ Markus Kinzler.
|
|
hansa
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Di 12.12.06 06:33
Matze muss sich genauer äußern. Will er irgendwas vor manuellen Eingaben ändern (automatisch, nur durch setzen des Dataset in den Update-Modus), dann ist der BU-Trigger angebracht. Ansonsten aber nicht.
_________________ Gruß
Hansa
|
|
mkinzler
      
Beiträge: 4106
Erhaltene Danke: 13
Delphi 2010 Pro; Delphi.Prism 2011 pro
|
Verfasst: Di 12.12.06 06:53
Er möchte den Zeitpunkt der letzten Änderung im Datensatz vermerken, wenn ein bestimmtes Feld nicht betroffen ist. Und da bietet sich ein (Before-)Trigger an, da ja der Datensatz u.U. geändert wird.
_________________ Markus Kinzler.
|
|
matze 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: Di 12.12.06 08:37
mkinzler hat folgendes geschrieben: | | Er möchte den Zeitpunkt der letzten Änderung im Datensatz vermerken, wenn ein bestimmtes Feld nicht betroffen ist. Und da bietet sich ein (Before-)Trigger an, da ja der Datensatz u.U. geändert wird. |
Ja genau. Das ist exakt das, was ich möchte.
Die letzte Änderung im Datensatz soll vermerkt werden, ausser wenn das Feld last_seen alleine gesetzt wird (wie in dem einen Query oben). Wenn andere Werte des Datensatzes verändert werden, will ich den Trigger ausführen lassen.
_________________ In the beginning was the word.
And the word was content-type: text/plain.
|
|
matze 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: Di 12.12.06 22:30
Also ich hab das Problem jetzt anders gelößt.
Ich bin aber auch noch auf eine andere Lösung gestoßen, die aber erst in Firebird 2 funktioniert:
SQL-Anweisung 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| if ((new.rbcard IS DISTINCT FROM old.rbcard) or (new.anrede IS DISTINCT FROM old.anrede) or (new.v_name IS DISTINCT FROM old.v_name) or (new.n_name IS DISTINCT FROM old.n_name) or (new.telefon IS DISTINCT FROM old.telefon) or (new.handy IS DISTINCT FROM old.handy) or (new.email IS DISTINCT FROM old.email) or (new.comment IS DISTINCT FROM old.comment) or (new.bonus IS DISTINCT FROM old.bonus)) then new.last_changed = current_timestamp; |
Also erst einmal muss man die new Values gegen old testen. Das müsste man dann mit IS DISTINC FROM machen, denn diese neue Funktion prüft auch NULL Werte gegeneinander.
_________________ In the beginning was the word.
And the word was content-type: text/plain.
Zuletzt bearbeitet von matze am Mi 13.12.06 10:21, insgesamt 1-mal bearbeitet
|
|
hansa
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Mi 13.12.06 00:15
matze hat folgendes geschrieben: | | ..aber erst in Firebird 5 funktioniert:.. |
Firebird 5 ?  Rücke mal den Link dazu raus.
Aber Matze, wat is jetzt ? Hört sich nicht so an, dass das jetzt zufriedenstellend läuft. Schon mal stored Procedure in Betracht gezogen ? So in der Richtung :
SQL-Anweisung 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| CREATE PROCEDURE PREISSP ( ID_KUNDE INTEGER, ID_ART INTEGER) as declare variable aendern integer; BEGIN AENDERN = -1; SELECT ID FROM PREIS WHERE (ID_KUNDE= :ID_KUNDE) AND (ID_ART= :ID_ART) INTO :AENDERN; IF (AENDERN < 0) THEN BEGIN INSERT INTO PREIS (ID_KUNDE,ID_ART,VP) VALUES (:ID_KUNDE,:ID_ART,:VP); END ELSE BEGIN UPDATE PREIS SET VP=:VP WHERE (ID_ART= :ID_ART) AND (ID_KUNDE= :ID_KUNDE); END SUSPEND; END^ |
Bei sowas muss man allerdings immer noch im Hinterkopf haben, dass egal wie : der Trigger lauert immer noch darauf, zuzuschlagen.
_________________ Gruß
Hansa
|
|
matze 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: Mi 13.12.06 10:24
wuuuups... Ich meine natürlich Firebird 2 (hab das auch oben gleich mal ausgebessert).
Ich habe das jetzt mit einem komplett anderen Ansatz gelößt und zwar:
SQL-Anweisung 1: 2: 3: 4: 5: 6: 7:
| CREATE TRIGGER USER_LAST_CHANGES_UPDATE FOR "USER" ACTIVE BEFORE UPDATE POSITION 0 AS begin if (new.last_seen = old.last_seen) then new.last_changed = current_timestamp; end |
Es wird also nur ausgeührt, wenn sich der last_seen Wert nicht ändert im Query. Das ist zwar nicht immer so praktisch für meine Verwendungszwecke, aber bis zur Umstellung auf Firebird 2 muss es halt reichen.
Also ich hab im Prinzip die Negation genommen. Nicht wenn sich bestimmte Felder ändern wird last_changes aktualisiert sondern nur wenn sich ein bestimmtes Feld nicht ändert.
_________________ In the beginning was the word.
And the word was content-type: text/plain.
|
|
hansa
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Mi 13.12.06 10:56
Du klebst zu sehr an den dummen Triggern.  Die haben zwei wichtige Nachteile : 1. keine Rückgabe-Parameter 2. keine lokalen Variablen. Es müsste doch möglich sein 2 Variablen in SP zu definieren (Seeen,Changes oder so) und diese dann auszuwerten und wie gewünscht die entsprechenden Felder zu setzen.
SQL-Anweisung 1: 2: 3: 4:
| if seen = 1 then set Update last_seen .... else ... |
_________________ Gruß
Hansa
|
|
matze 
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: Mi 13.12.06 11:01
ja ich werde mir mal Stored Procedures ansehen aber im Moment geht das mit den Triggern wunderbar !
_________________ In the beginning was the word.
And the word was content-type: text/plain.
|
|