Information ausblenden
Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm

Trigger... mit berechnetem Wert weiter rechnen?

Dieses Thema im Forum "Microsoft SQL Server" wurde erstellt von Effie, 20 Februar 2013.

  1. Effie

    Effie Benutzer

    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
     
  2. ukulele

    ukulele Datenbank-Guru

    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.
     
  3. Effie

    Effie Benutzer

    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 ?
     
  4. akretschmer

    akretschmer Datenbank-Guru


    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
     
    PLSQL_SQL gefällt das.
  5. Effie

    Effie Benutzer

    Wie sollte so eine view denn aussehen?
     
  6. akretschmer

    akretschmer Datenbank-Guru

    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
     
  7. ukulele

    ukulele Datenbank-Guru

    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.
     
  8. akretschmer

    akretschmer Datenbank-Guru

    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
     
  9. ukulele

    ukulele Datenbank-Guru

    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.
     
    PLSQL_SQL gefällt das.
  10. ukulele

    ukulele Datenbank-Guru

    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.
     
  11. ukulele

    ukulele Datenbank-Guru

    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
     
    PLSQL_SQL gefällt das.
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden