Trigger... mit berechnetem Wert weiter rechnen?

Effie

Benutzer
Beiträge
13
Hallo Zusammen,

ich habe einen Trigger der zunächst 3 Werte berechnet(PCPlan, PCPrep,PCExec)
diese 3 berechneten Werte sollen dann addiert werden (PCTot). Ist das möglich? wenn ja, wo ist mein Fehler??

Mein Trigger:
CREATE TRIGGER [dbo].[TR_BaseData]
On [dbo].[Base]
After Insert, Update, Delete
As
Begin



Update Base
SET PCPlan=
case
when (select Inserted.HrsPlan from Inserted)<>0
AND (select Inserted.CstPerHrPlan from Inserted)<>0
then (select Inserted.HrsPlan*inserted.CstPerHrPlan from Inserted)
When (select Inserted.HrsPlan from Inserted)=0
Or (select Inserted.CstPerHrPlan from Inserted)=0
Then 0
End


Update Base
SET PCPrep=
case
when (select Inserted.HrsPrep from Inserted)<>0
AND (select Inserted.CstPerHrPrep from Inserted)<>0
then (select Inserted.HrsPrep*inserted.CstPerHrPrep from Inserted)
When (select Inserted.HrsPrep from Inserted)=0
Or (select Inserted.CstPerHrPrep from Inserted)=0
Then 0
End


Update Base
SET PCExec=
case
when (select Inserted.HrsExec from Inserted)<>0
AND (select Inserted.CstPerHrExec from Inserted)<>0
then (select Inserted.HrsExec*inserted.CstPerHrExec from Inserted)
When (select Inserted.HrsExec from Inserted)=0
Or (select Inserted.CstPerHrExec from Inserted)=0
Then 0
END



Update Base
SET PCTot=
case
when (select Inserted.PCPlan from Inserted)<>0
OR (select Inserted.PCPrep from Inserted)<>0
OR (select Inserted.PCExec from Inserted)<>0
then (select Inserted.PCPlan+Inserted.PCPrep+Inserted.PCExec from Inserted)
When (select Inserted.PCPlan from Inserted)=0
AND (select Inserted.PCPrep from Inserted)=0
AND (select Inserted.PCExec from Inserted)=0
Then 0
End

End



Hoffe mir kann jemand helfen
 
Werbung:

ukulele

Datenbank-Guru
Beiträge
4.702
Muss wirklich jedesmal die komplette Tabelle aktualisiert werden?
Können auch NULL Werte auftreten?
Warum arbeitest du nicht mit einer Sicht oder berechneten Spalten?
Geht nur die PCTot Berechnung nicht die anderen aber schon?

Abgesehen davon feuert dein Trigger zwar bei ON DELETE, wird aber nichts aus der INSERTED Tabelle lesen können, die gibt es nur bei INSERT oder UPDATE. Ein Trigger feuert auch nur einmal (beim ersten Datensatz) auch wenn der auslösende Befehl mehrere Datensätze betrifft, eventuell ist das dein Problem.
 

Effie

Benutzer
Beiträge
13
In erster linie weil ich nicht weiss wie es geht, und chef einmal sagte : bau einen trigger^^

Also die werte pcplan pcprep und pcecex werden problemlos berechnet und angezeigt.
Dann allerdings soll sich ja aus diesen drei ergebnissen pctot ergeben durch addition..
Nur leider nimmt er dann nicht die ergebnisse sondern den wert bevor die berechnet wurden also 0.
Rechnet dann 0+0+0 ...

Muss ich die werte pcplan, pcprep, pcexec vielleicht erst zwischenspeichern irgendwie ?
 

akretschmer

Datenbank-Guru
Beiträge
9.736
In erster linie weil ich nicht weiss wie es geht, und chef einmal sagte : bau einen trigger^^

Also die werte pcplan pcprep und pcecex werden problemlos berechnet und angezeigt.
Dann allerdings soll sich ja aus diesen drei ergebnissen pctot ergeben durch addition..
Nur leider nimmt er dann nicht die ergebnisse sondern den wert bevor die berechnet wurden also 0.
Rechnet dann 0+0+0 ...

Muss ich die werte pcplan, pcprep, pcexec vielleicht erst zwischenspeichern irgendwie ?


Aus dem Bauch heraus würde ich sagen: führe in der Trigger-Funktion Variablen mit, das sollte dann einfach sein. Aber wenn ich *etwas* genauer überlege, muß ich mich da ukulele anschließen: warum eine Spalte aus den Werten von anderen Spalten berechnen? Das ist redundant, sowas macht man in der Abfrage bzw. via VIEW.

Und dann kommt dann noch der andere Hinweis von ukulele: der Trigger wird wohl nur per Statement gefeuert, per Row kann M$SQL wohl nicht, das wurde hier schon mal durchgekaut. (was ich ja für ziemlich schwach halte ...)


Andreas
 

akretschmer

Datenbank-Guru
Beiträge
9.736
Wie sollte so eine view denn aussehen?

In PG geht es so:

Code:
test=*# create table effie (a int, b int, c int);
CREATE TABLE
Time: 1,121 ms
test=*#
test=*# insert into effie values (1,2,3);
INSERT 0 1
Time: 0,332 ms
test=*# create view view_effie as select a,b,c,a+b+c as summe from effie;
CREATE VIEW
Time: 61,584 ms
test=*# select * from view_effie ;
 a | b | c | summe
---+---+---+-------
 1 | 2 | 3 |     6
(1 row)

M$SQL kenne ich nicht, dürfte aber ähnlich gehen.


Andreas
 

ukulele

Datenbank-Guru
Beiträge
4.702
Mit der View geht es einfacher, allerdings hat man häufig das Problem das man nicht beeinflussen kann wo sich die Endanwendung dann die Werte her holt. Wenn du aber Zugriff auf die Anwendung hast, dann ist eine View einfacher.

Auch das mit den Variablen ist einfach und sinnvoll.

Deine Berechnung für PCTot ist auch Murks. Du schreibst die Werte ja erst durch den Trigger in die DB, darfst also erst in einem Folgetrigger aus Inserted wieder die Werte holen. Dazu musst du aber jede Zeile einzeln schreiben und bei jeder Berechnung jedesmal den neuen Trigger abfeuern. Variablen sind hier der schnellste Weg zum Ziel.
 

akretschmer

Datenbank-Guru
Beiträge
9.736
Mit der View geht es einfacher, allerdings hat man häufig das Problem das man nicht beeinflussen kann wo sich die Endanwendung dann die Werte her holt. Wenn du aber Zugriff auf die Anwendung hast, dann ist eine View einfacher.

Auch das mit den Variablen ist einfach und sinnvoll.

Deine Berechnung für PCTot ist auch Murks. Du schreibst die Werte ja erst durch den Trigger in die DB, darfst also erst in einem Folgetrigger aus Inserted wieder die Werte holen. Dazu musst du aber jede Zeile einzeln schreiben und bei jeder Berechnung jedesmal den neuen Trigger abfeuern. Variablen sind hier der schnellste Weg zum Ziel.

Geht sowas wie folgt nicht?

Code:
test=# create table foo (a int, b int, summe int);
CREATE TABLE
Time: 13,694 ms
test=*# create function foo_summe() returns trigger as $$begin new.summe=new.a+new.b;return new;end;$$language plpgsql;
CREATE FUNCTION
Time: 0,499 ms
test=*# create trigger trg_foo before insert on foo for each row execute procedure foo_summe();
CREATE TRIGGER
Time: 0,412 ms
test=*# insert into foo (a,b) values (1,2),(3,4),(5,6);
INSERT 0 3
Time: 7,961 ms
test=*# select * from foo;
 a | b | summe
---+---+-------
 1 | 2 |     3
 3 | 4 |     7
 5 | 6 |    11
(3 rows)

Ja, es gehen wohl nur statement-Trigger, aber kann man nicht auf NEW (und bei Updates OLD) zugreifen?

Andreas
 

ukulele

Datenbank-Guru
Beiträge
4.702
Müsste gehen bis auf das for each row. Aber es bedarf eigentlich keiner Funktion für eine Addition. Das Problem ist das der ursprüngliche Trigger von Effie erst a und b berechnet und in die Tabelle schreibt, also in der INSERTED Tabelle des urprünglichen Triggers unmöglich diese Werte schon stehen können. Aus eben dieser versucht er/sie diese aber zu holen.
Der Trigger müsste beim schreiben einen weiteren Trigger anstoßen, der die Summe berechnet. Oder es werden einfach innerhalb des Triggers Variablen deklariert und genuzt, was sowohl Übersicht als auch Performance bringen sollte im Vergleich mit mehreren, verschachtelten Triggern.
 

ukulele

Datenbank-Guru
Beiträge
4.702
Außerdem fällt mir grade auf werden alle Einträge der Tabelle immer mit den errechneten Werten durch den Trigger beschrieben. Das kann ja so nicht sinnvoll sein.
 
Werbung:

ukulele

Datenbank-Guru
Beiträge
4.702
Kurz gesagt:
Code:
ALTER TRIGGER [dbo].[TR_BaseData]
ON [dbo].[Base]
AFTER INSERT, UPDATE
AS
BEGIN
    DECLARE    @PrimaryID UNIQUEIDENTIFIER,
            @PCPlan INT,
            @PCPrep INT,
            @PCExec INT
 
    SELECT    @PrimaryID = PrimaryID, -- ID deines Datensatzes übergeben
            @PCPlan = isnull(HrsPlan,0) * isnull(CstPerHrPlan,0),
            @PCPrep = isnull(HrsPrep,0) * isnull(CstPerHrPrep,0),
            @PCExec = isnull(HrsExec,0) * isnull(CstPerHrExec,0)
    FROM    INSERTED
 
    UPDATE    Base
    SET        PCPlan = @PCPlan,
            PCPrep = @PCPrep,
            PCExec = @PCExec,
            PCTot = @PCPlan + @PCPrep + @PCExec
    WHERE    PrimaryID = @PrimaryID
END
 
Oben