Anzeige:
Ergebnis 1 bis 8 von 8

Thema: TRIGGER (DB2) Problem!

  1. #1
    Registrierter Benutzer
    Registriert seit
    06.07.2005
    Beiträge
    14

    Exclamation TRIGGER (DB2) Problem!

    Habe mein Problem durch die Suche nicht finden können. Hoffe, Ihr könnt mir helfen!

    Ich habe eine Datenbasis, in der einige Waren (deren Stückzahl und Preis etc.) aufgeführt sind. Nun will ich einen Trigger (after update) erstellen, der Rabatt für eine Ware erlässt, wenn die Stückzahl eine bestimmte Höhe erreicht. Habe mir folgenden Code überlegt:
    Code:
    CREATE TRIGGER Waren_Update AFTER UPDATE OF Stueckzahl ON Waren
    REFERENCING OLD AS alt NEW AS neu
    FOR EACH ROW MODE DB2SQL
    UPDATE Waren
    SET Preis = (Preis * 0.7)
    WHERE (neu.Stueckzahl>alt.Stueckzahl AND neu.Stueckzahl > 500 );
    Allerdings verringert sich nun der Rabatt bei allen Waren, sobald ein Update gemacht wird. Wie kann ich also anweisen, dass der Rabatt nur bei der Ware gewährt wird, deren Stückzahl gestiegen ist?

    Brauche dringend Rat!

  2. #2
    Registrierter Benutzer
    Registriert seit
    06.07.2005
    Beiträge
    14

    Thumbs up problem gelöst!

    Wenn es interessiert, habe das Problem gelöst!
    Code:
    CREATE TRIGGER Waren_Update AFTER UPDATE OF Stueckzahl ON Waren
    REFERENCING NEW AS neu
    FOR EACH ROW MODE DB2SQL
    WHEN(neu.Stueckzahl > 500 )
    UPDATE Waren
    SET PREIS = (PREIS * 0.7)
    WHERE (Stueckzahl = neu.Stueckzahl);
    Die Bedingung muss also sinnvollerweise in die WHEN Klausel und bei WHERE wird durch die Referenz auf neu selektiert, d.h. dass nur die Waren, die verändert wurden, "gesetet" werden.
    So, Monolog zu Ende!

  3. #3
    Registrierter Benutzer
    Registriert seit
    24.12.2001
    Ort
    anywhere before EOF
    Beiträge
    236
    Aus versehen 2 mal gepostet, sorry...
    Geändert von sticky bit (16-02-2006 um 15:10 Uhr)
    chmod -R +t /*

  4. #4
    Registrierter Benutzer
    Registriert seit
    24.12.2001
    Ort
    anywhere before EOF
    Beiträge
    236
    Habe keine Ahnung von DB2, aber meiner Meinung nach machst du da gehörig was falsch, oder willst was erreichen was mir unverständlich ist....

    Also ich gehe gleich aufs zweite Beispiel ein. Angenommen die Tabelle sieht mal gerade so aus (Inhaltlich):
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        100 |  100.00 |
    |  2 |        230 |   20.00 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    Dann kommt ein Update auf die Stückzahlen sagen wir mal vom 2.:
    Code:
    UPDATE waren
                SET stueckzahl = 600
                WHERE id = 2;
    Dann sieht das so aus:
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        100 |  100.00 |
    |  2 |        600 |   14.00 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    So weit so gut, das wolltest du ja.
    Aber jetzt kommt wieder eine Aktualisierung, z. B. auf den ersten:
    Code:
    UPDATE waren
                SET stueckzahl = 600
                WHERE id = 1;
    Und deine Tabelle wird so aussehen:
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        600 |   70.00 |
    |  2 |        600 |    9.80 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    Na, fällsts auf? der zweite hat genau so viele Stück wie der erste und wird natürlich auch billiger, weil du immer die ganze Tabelle in deinem Trigger UPDATEst.

    Und wenn ich jetzt noch mal ein UPDATE auf den 2. mache:
    Code:
    UPDATE waren
                SET stueckzahl = 601
                WHERE id = 2;
    Dann wird der gleich noch mal billiger (die anderen in dem Fall allerdings nicht weil die keine 601 Stück habe):
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        600 |   70.00 |
    |  2 |        601 |    6.86 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    Und ich weiss ja nicht ob das alles so gewollt ist? Wenn ja dann sag mal welcher Laden das ist, vielleicht bestell ich demnächst recht viel bei euch...
    Oder erklär mir den Sinn dahinter ich verstehs jeden Fall nicht.

    Aber Spass bei Seite entweder du machst das UPDATE in deinem Trigger vom Primärschlüssel des geänderten Datensatzes abhängig (ich hab hier mal einfach `id` angenommen, weiss nicht wie das bei dir aussieht). Oder aber, ich hoffe das geht unter DB2 auch, mach das ganze über eine Zuweisung an die neue Spalte, ein zeilenweise Trigger ists ja eh schon...
    Ich versuchs mal an Hand deines Beispiels zu erraten wie das aussehen könnte in DB2-Syntax:
    Code:
    CREATE TRIGGER waren_update
                          AFTER UPDATE OF stueckzahl ON waren
                          REFERENCING OLD AS alt
                                             NEW AS neu
                          FOR EACH ROW
                          MODE DB2SQL
        IF alt.stueckzahl <= 500
           AND neu.stueckzahl  > 500 THEN
          neu.preis := alt.preis * .7;
        END IF;
    Die Bedingung des IFs kannste wenn dus schicker findest oder es vielleicht performancetechnisch was bringt auch noch ganz ins WHEN schreiben:
    Code:
    CREATE TRIGGER waren_update
                          AFTER UPDATE OF stueckzahl ON waren
                          REFERENCING OLD AS alt
                                             NEW AS neu
                          FOR EACH ROW
                          MODE DB2SQL
                          WHEN (alt.stueckzahl <= 500
                                AND neu.stueckzahl  > 500)
        neu.preis := alt.preis * .7;
    Aber auf jeden Fall sollte das ganze, wenn ich den Sinn richtig verstanden habe nur dann passieren wenn die Stückzahl zum ersten mal auf ein Zahl die grösser als 500 ist steigt und nicht dauernd wenn sie auf irgendwas grösser 500 geändert wird.

    Ah ja, wie sieht das ganze eigentlich vice versa aus? Ich meine was wenn die Stückzahl von was grösser 500 wieder auf was kleiner gleich 500 geht, soll dann der Preis wieder mehr werden?
    chmod -R +t /*

  5. #5
    Registrierter Benutzer
    Registriert seit
    06.07.2005
    Beiträge
    14
    Zitat Zitat von sticky bit
    Also ich gehe gleich aufs zweite Beispiel ein. Angenommen die Tabelle sieht mal gerade so aus (Inhaltlich):
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        100 |  100.00 |
    |  2 |        230 |   20.00 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    Dann kommt ein Update auf die Stückzahlen sagen wir mal vom 2.:
    Code:
    UPDATE waren
                SET stueckzahl = 600
                WHERE id = 2;
    Dann sieht das so aus:
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        100 |  100.00 |
    |  2 |        600 |   14.00 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    So weit so gut, das wolltest du ja.
    Aber jetzt kommt wieder eine Aktualisierung, z. B. auf den ersten:
    Code:
    UPDATE waren
                SET stueckzahl = 600
                WHERE id = 1;
    Und deine Tabelle wird so aussehen:
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        600 |   70.00 |
    |  2 |        600 |    9.80 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    Na, fällsts auf? der zweite hat genau so viele Stück wie der erste und wird natürlich auch billiger, weil du immer die ganze Tabelle in deinem Trigger UPDATEst.
    Ich weiss ja nicht, mit was für einer Datenbank Du arbeitest, aber bei uns hat es funktioniert. Meinst, ich stelll einen Code rein, den ich nicht getestet habe?

    Es wird eben nicht die ganze Tabelle geupdatet! Das wird durch die WHERE-Klausel erreicht, indem man (am besten nimmt man den Schlüssel) den alten Wert mit dem neuen vergleicht. Also z.B. Art_Code = neu.Art_Code
    Zitat Zitat von sticky bit
    Und wenn ich jetzt noch mal ein UPDATE auf den 2. mache:
    Code:
    UPDATE waren
                SET stueckzahl = 601
                WHERE id = 2;
    Dann wird der gleich noch mal billiger (die anderen in dem Fall allerdings nicht weil die keine 601 Stück habe):
    Code:
    .___________________________.
    | id | stueckzahl | preis   |
    +----+------------+---------+
    |  1 |        600 |   70.00 |
    |  2 |        601 |    6.86 |
    |  3 |         10 | 5000.00 |
    '----+------------+---------'
    Und ich weiss ja nicht ob das alles so gewollt ist? Wenn ja dann sag mal welcher Laden das ist, vielleicht bestell ich demnächst recht viel bei euch...
    Oder erklär mir den Sinn dahinter ich verstehs jeden Fall nicht.
    Damit hast Du recht. Das ist uns später auch nocht aufgefallen. Wir haben das gelöst, indem wir etwas in der Art wie: (Stueckzahl<=500 AND neu.Stueckzahl>500) geschrieben haben.
    Zitat Zitat von sticky bit
    Ah ja, wie sieht das ganze eigentlich vice versa aus? Ich meine was wenn die Stückzahl von was grösser 500 wieder auf was kleiner gleich 500 geht, soll dann der Preis wieder mehr werden?
    Ja, genau. Ich habe den Rückfall des Bestandes nicht erwähnt, weil der Fall analog ist.

    Danke Dir für Deinen ausführlichen Kommentar!

  6. #6
    Registrierter Benutzer
    Registriert seit
    06.07.2005
    Beiträge
    14

    P.s.

    Zitat Zitat von sticky bit
    Code:
    CREATE TRIGGER waren_update
                          AFTER UPDATE OF stueckzahl ON waren
                          REFERENCING OLD AS alt
                                             NEW AS neu
                          FOR EACH ROW
                          MODE DB2SQL
                          WHEN (alt.stueckzahl <= 500
                                AND neu.stueckzahl  > 500)
        neu.preis := alt.preis * .7;
    Übrigens funktioniert (zumindest unter DB2) die Referenz auf die alte Stückzahl auch "ohne referencing old as alt"! Also:
    Code:
    WHEN (stueckzahl <= 500
                                AND neu.stueckzahl  > 500)
    Gibt es da bei anderen DBMS Probleme?

  7. #7
    Registrierter Benutzer
    Registriert seit
    24.12.2001
    Ort
    anywhere before EOF
    Beiträge
    236
    Naja, grundsätzlich ist es ja egal ob die ganze Tabelle oder nur eine Zeile aktualisiert wird. Nur denke ich, dass es a) von der Performance einen Unterschied machen könnte, schliesslich weiss die Datenbank beim Auslösen des Triggers schon welche Zeilen von der Aktualisierung die den Trigger auslöst betroffen sind und sollte dafür eigentlich noch Referenzen im Speicher haben. Wenn man dann genau jene Menge noch mal zusätzlich im Trigger aktualisieren möchte, dann dürfte das schneller gehen das über eben jene Zuweisungsmethode auf die dem Trigger zugehörige Zeile zu machen als ein Query über die ganze Tabelle laufen zu lassen, wo ja theoretisch auch andere Zeilen betroffen sein könnten und die Datenbank noch mal nach sehen muss was denn jetzt gemeint ist. Klar, wenn man nach dem Primärschlüssel einschränkt sollte da ein Index drauf sein, dass das recht flott geht und vielleicht schaffts im dem Fall vielleicht sogar der Optimizer zu erkennen, dass er sich den Lookup überhaupt sparen kann und gleich die Zeile annimmt die zum Trigger gehört, aber da wär ich mir halt nicht wirklich sicher.

    Code:
    CREATE TRIGGER Waren_Update AFTER UPDATE OF Stueckzahl ON Waren
    REFERENCING NEW AS neu
    FOR EACH ROW MODE DB2SQL
    WHEN(neu.Stueckzahl > 500 )
    UPDATE Waren
    SET PREIS = (PREIS * 0.7)
    WHERE (Stueckzahl = neu.Stueckzahl);
    Ich weiss ja nicht, mit was für einer Datenbank Du arbeitest, aber bei uns hat es funktioniert. Meinst, ich stelll einen Code rein, den ich nicht getestet habe?

    Es wird eben nicht die ganze Tabelle geupdatet! Das wird durch die WHERE-Klausel erreicht, indem man (am besten nimmt man den Schlüssel) den alten Wert mit dem neuen vergleicht. Also z.B. Art_Code = neu.Art_Code
    Wenn du nach dem Primärschlussel einschränkst passiert nichts "falsches". War aber aus deinem Code den Post davor nicht ersichtlich, da gehst du nach der Stückzahl (die wohl kaum primärschlüsselfähig sein dürfte, zumindest wenn ich von der gewöhnlich Bedeutung einer Stückzahl ausgehe).
    Darum hab ich darauf hingewiesen, dass du da vielleicht beim Testen was über sehen hast. Mit den entsprechenden Daten mag das durchaus auch wenn man nur auf die Stückzahl einschränkt so aussehen als wäre alles bestens. Das Problem tritt ja erst auf, wenn die geupdatete Stückzahl schon da ist, was beim Testen ja nicht der Fall sein hätte müssen. Im Betrieb passiert das aber dann mal und dann weiss keiner was los ist und die Ware 'Sünhaftteure Stereoanlage' mittlerweile nur noch einen Preis von 50 cent hat...

    Übrigens funktioniert (zumindest unter DB2) die Referenz auf die alte Stückzahl auch "ohne referencing old as alt"! Also:
    Code:
    WHEN (stueckzahl <= 500 AND neu.stueckzahl > 500)
    Gibt es da bei anderen DBMS Probleme?
    Ja, Oracle zickt da rum. Zumindest hab ichs nicht hinbekommen ihm das "wegzunehmen" ohne Fehlermeldung.
    Ausserdem ists schöner zu lesen, meiner Meinung nach, aber das ist ganz klar Ansichstssache!
    chmod -R +t /*

  8. #8
    Registrierter Benutzer Avatar von mwanaheri
    Registriert seit
    28.10.2003
    Ort
    Bayreuth
    Beiträge
    569
    Ich würde übrigens vorschlagen, den Rabatt als Rabatt einzurichten und nicht direkt den Preis zu manipulieren.
    So bleibt der eigentliche Preis, wie er nun mal ist, und der zu zahlende Preis bestimmt sich aus eigentlichem Preis und dem Rabatt.
    Der Rabatt ist entweder eine Prozentzahl (standard: 0%) oder ein Float (standard: 1).
    letzteres ist schneller zu rechnen, denke ich.
    Das Ziel ist das Ziel.

Lesezeichen

Berechtigungen

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