Autor Beitrag
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: 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 !

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: Mo 11.12.06 22:26 
Ich würde old. mit new. vergleichen.

_________________
Markus Kinzler.
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Di 12.12.06 04:44 
user profile iconmatze 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 :

ausblenden 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. :shock: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Di 12.12.06 08:37 
user profile iconmkinzler 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: 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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Mi 13.12.06 00:15 
user profile iconmatze hat folgendes geschrieben:
..aber erst in Firebird 5 funktioniert:..


Firebird 5 ? :shock: Rücke mal den Link dazu raus. :lol:

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 :

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: 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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Mi 13.12.06 10:56 
Du klebst zu sehr an den dummen Triggern. 8) 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.

ausblenden SQL-Anweisung
1:
2:
3:
4:
if seen = 1 then set  /* ansonsten 0 */
  Update last_seen ....
else /* andere Felder */
...

_________________
Gruß
Hansa
matze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: 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.