MS SQL - Trigger bei mehrzeiligen Operationen

TS-JC

Erfahrenes Mitglied
Hallo zusammen

hab mal ne schöne schwere(?) Frage für euch :-)

Also ich habe ein Data Warehouse, mit einer Factentabelle und mehreren Dimensionen.
Jedesmal wenn die Faktentabelle nun einen Insert oder Update bekommt brauche ich einen Trigger.

Und zwar habe ich eine Aggregat-Tabelle in der ich die Daten verdichten also verkleinern möchte.

Problem ist nun das es auch Updates über mehrere Zeilen der Faktentabelle gibt.
Z.B. wenn alle Zeilen mir der Zeit_ID = 1 neue Kosten bekommen.

Den Trigger den ich entwickelt habe, der meldet mir dann immer:
Error: Die Unterabfrage hat mehr als einen Wert zurückgegeben. Das ist nicht zulässig, wenn die Unterabfrage auf =, !=, <, <=, > oder >= folgt oder als Ausdruck verwendet wird.

Bissle gesucht im Netz, leider sehr wenig zu finden, ausser dem hier:
http://msdn2.microsoft.com/de-de/library/ms190752(SQL.90).aspx
Dort steht nun das Cursor schlecht für die Performance wären und man lieber "rowsetbasierte Logik" nutzen soll, was auch immer das heissen mag.

Naja, vielleicht hat ja jemand einen Ansatz für mich :-)
Ich versuche mich derweil trotzdem mal an der Cursor Lösung.

PHP:
CREATE TRIGGER AGG_TRIGGER ON DW_FACT FOR INSERT AS
BEGIN
DECLARE @ZEIT_ID INT, @EINNAHME_ID INT, @DATUM DATETIME, @WOCHE INT, @EINNAHME_ART CHAR(20), @W_EINNAHMEN MONEY, @W_KOSTEN MONEY
        SELECT @ZEIT_ID = (SELECT ZEIT_ID FROM INSERTED)
        SELECT @EINNAHME_ID = (SELECT EINNAHME_ID FROM INSERTED)
        SELECT @DATUM = (SELECT DATUM FROM DW_ZEIT WHERE ZEIT_ID = @ZEIT_ID)
        SELECT @EINNAHME_ART = (SELECT EINNAHME_ART FROM DW_EINNAHMEART WHERE EINNAHME_ID = @EINNAHME_ID)

        SELECT @WOCHE = (SELECT DATEPART(WK, z.DATUM) woche
                                FROM DW_ZEIT z, DW_FACT f
                                WHERE  z.ZEIT_ID = @ZEIT_ID
                                       AND f.EINNAHME_ID = @EINNAHME_ID
                                GROUP BY DATEPART(YYYY, z.DATUM), DATEPART(WK, z.DATUM))

        SELECT @W_EINNAHMEN = (SELECT SUM(F.BETRAG) FROM DW_FACT F WHERE F.ZEIT_ID = @ZEIT_ID AND F.EINNAHME_ID = @EINNAHME_ID)
        SELECT @W_KOSTEN = (SELECT SUM(F.KOSTEN) FROM DW_FACT F WHERE F.ZEIT_ID = @ZEIT_ID AND F.EINNAHME_ID = @EINNAHME_ID)

-- vorerst auskommentiert, das Problem is ja auch weiter oben
--        IF (SELECT W_EINNAHMEN FROM DW_AGGREGAT WHERE DATUM = @DATUM AND ART = @EINNAHME_ART) > 0
--                UPDATE DW_WOCHEN_AGGREGAT SET W_EINNAHMEN = @W_EINNAHMEN + W_EINNAHMEN, W_KOSTEN = @W_KOSTEN + W_KOSTEN WHERE DATUM = @DATUM AND ART = @EINNAHME_ART
--        ELSE INSERT INTO DW_WOCHEN_AGGREGAT VALUES (@DATUM, @EINNAHME_ART, @W_EINNAHMEN, @W_KOSTEN)
END
 
Habs nun mit nem Cursor gelöst, klappt auch wunderbar, zumindest beim Insert.
Hier meine aufgebohrte Lösung, falls mal irgendwann jemand nen ähnliches Prob hat :)

PHP:
CREATE TRIGGER AGG_TRIGGER ON DW_FACT AFTER INSERT AS

DECLARE @ZEIT_ID INT,
        @EINNAHME_ID INT,
        @WOCHE INT,
        @EINNAHME_ART CHAR(20),
        @W_EINNAHMEN MONEY,
        @W_KOSTEN MONEY,
        @TEMP INT,
        @KOSTEN MONEY,
        @EINNAHMEN MONEY

        BEGIN
                DECLARE FACT CURSOR FOR
                        SELECT * FROM INSERTED
                OPEN FACT

                FETCH NEXT FROM FACT INTO @ZEIT_ID, @TEMP, @EINNAHME_ID, @EINNAHMEN, @TEMP, @KOSTEN
                        SELECT @EINNAHME_ART = (SELECT EINNAHME_ART FROM DW_EINNAHMEART WHERE EINNAHME_ID = @EINNAHME_ID)
                        SELECT @WOCHE = (SELECT DATEPART(WK, Z.DATUM) WOCHE
                                FROM DW_ZEIT Z, DW_FACT F
                                WHERE  Z.ZEIT_ID = @ZEIT_ID
                                       AND F.EINNAHME_ID = @EINNAHME_ID
                                GROUP BY DATEPART(YYYY, Z.DATUM), DATEPART(WK, Z.DATUM))

                        IF (SELECT W_EINNAHMEN FROM DW_WOCHEN_AGGREGAT WHERE WOCHE = @WOCHE AND ART = @EINNAHME_ART) > 0
                                UPDATE DW_WOCHEN_AGGREGAT SET W_EINNAHMEN = W_EINNAHMEN + @EINNAHMEN, W_KOSTEN = W_KOSTEN + @KOSTEN WHERE WOCHE = @WOCHE AND ART = @EINNAHME_ART
                        ELSE INSERT INTO DW_WOCHEN_AGGREGAT VALUES (@WOCHE, @EINNAHME_ART, @EINNAHMEN, @KOSTEN)

                WHILE @@FETCH_STATUS = 0
                BEGIN
                        FETCH NEXT FROM FACT INTO @ZEIT_ID, @TEMP, @EINNAHME_ID, @EINNAHMEN, @TEMP, @KOSTEN
                        IF @@FETCH_STATUS = -1
                                BREAK

                        SELECT @EINNAHME_ART = (SELECT EINNAHME_ART FROM DW_EINNAHMEART WHERE EINNAHME_ID = @EINNAHME_ID)
                        SELECT @WOCHE = (SELECT DATEPART(WK, Z.DATUM) WOCHE
                                FROM DW_ZEIT Z, DW_FACT F
                                WHERE  Z.ZEIT_ID = @ZEIT_ID
                                       AND F.EINNAHME_ID = @EINNAHME_ID
                                GROUP BY DATEPART(YYYY, Z.DATUM), DATEPART(WK, Z.DATUM))

                        IF (SELECT W_EINNAHMEN FROM DW_WOCHEN_AGGREGAT WHERE WOCHE = @WOCHE AND ART = @EINNAHME_ART) > 0
                                UPDATE DW_WOCHEN_AGGREGAT SET W_EINNAHMEN = W_EINNAHMEN + @EINNAHMEN, W_KOSTEN = W_KOSTEN + @KOSTEN WHERE WOCHE = @WOCHE AND ART = @EINNAHME_ART
                        ELSE
                        INSERT INTO DW_WOCHEN_AGGREGAT VALUES (@WOCHE, @EINNAHME_ART, @EINNAHMEN, $0)

                END
                CLOSE FACT
        END
 

Neue Beiträge

Zurück