Trigger mit UPDATE() Bedingung feuert bei NULL-Wert

ukulele

Datenbank-Guru
Beiträge
4.702
Hallo Forum, ich hoffe ich finde hier dauerhaft Unterstützung zu den unzähligen SQL Merkwürdigkeiten in meinem Dasein ;).

Folgendes Szenario (stark vereinfacht):

Tabellen:
A, B, C
Spalten in A:
insert_value_in_B varchar NULL
insert_value_in_C varchar NULL
Spalten in B:
value_in_B varchar NOT NULL
Spalten in C:
value_in_C varchar NOT NULL
Trigger:
trigger_a
trigger_b

Trigger a und b haben die selbe Funktionsweise.
PHP:
AFTER UPDATE, INSERT
AS
IF        UPDATE(insert_value_in_X)
BEGIN
           Schreibe insert_value_in_X in Tabelle X
END

Erstelle ich jetzt einen neuen Eintrag mit einem Wert in insert_value_in_B trägt Trigger B diesen Wert in der Tabelle B ein. Trigger A und Tabelle A bleiben untätig. Versuche ich nur in A einen Eintrag zu schreiben reagiert Trigger B und versucht einen NULL-Wert in Tabelle B zu schreiben. Die Trigger sind wie gesagt vom Aufbau her nahezu identisch. Ich habe nun noch eine IF Abfrage auf NULL Werte in B eingebaut, klappt auch, aber das ganze ergibt für mich keinen Sinn. Hat jemand eine Idee?
 
Werbung:

Charly

Datenbank-Guru
Beiträge
306
AW: Trigger mit UPDATE() Bedingung feuert bei NULL-Wert

Hallo ukulele,

kannst Du die Original Create-Anweisungen der Tabellen und Trigger einstellen.

So wie Du das dargestellt hast kann ich den Fehler nicht finden.

Gruß Charly

PS: Sorry für die späte Antwort.
 

ukulele

Datenbank-Guru
Beiträge
4.702
AW: Trigger mit UPDATE() Bedingung feuert bei NULL-Wert

Soooo hat etwas gedauert bis ich mich nochmal mit dem Problem auseinander gesetzt habe. Ich bin durch Zufall auf den Unterschied in beiden Triggern aufmerksam geworden, siehe Makierung. Allerdings besteht das Problem weiterhin, denn beide Trigger scheinen damit auf NULL-Werte zu reagieren.

Folgendes sei noch gesagt: Ich habe quasi "Hilfsspalten" in meine Haupttabelle eingebaut um Werte aus meiner Eingabemaske in der Anwendung per Trigger in die Nebentabellen zu schreiben. Ist sicher DB technisch wenig elegant aber bequemer für den Nutzer. Alle Spalten Namens "insert_xxx" sind nichts weiter als leere Hilfsspalten zu diesem Zweck. Die Werte werden dann in gleichnamige Spalten (ohne insert_) in die Nebentabelle geschrieben und danach gelöscht.

PHP:
CREATE TRIGGER    [dbo].[unt_insert_into_ruf]
    ON            [dbo].[unt]
    AFTER UPDATE, INSERT
AS
IF        UPDATE(insert_ruf_nummer)
-- Komischer Fehler, Trigger auf UPDATE() reagiert auf NULL,
-- daher Behelfslösung
-- AND (    SELECT    insert_ruf_nummer
--        FROM    INSERTED ) IS NOT NULL
BEGIN
        SET NOCOUNT ON;

        DECLARE    @pk UNIQUEIDENTIFIER
        DECLARE    @insert_ruf_ort VARCHAR(10)
        DECLARE    @insert_ruf_nummer VARCHAR(20)
        DECLARE    @insert_ruf_durchwahl VARCHAR(6)
        DECLARE    @insert_ruf_typ_anschluss VARCHAR(21)
        DECLARE    @insert_ruf_typ_geraet VARCHAR(20)
        DECLARE    @insert_ruf_typ_outlook VARCHAR(20)
        DECLARE    @insert_ruf_quelle VARCHAR(20)
        DECLARE    @insert_ruf_von DATETIME
        DECLARE    @insert_ruf_fk_per UNIQUEIDENTIFIER
        DECLARE    @insert_ruf_fk_adr UNIQUEIDENTIFIER
        DECLARE    @error VARCHAR(255)

        SELECT    @pk = pk,
                @insert_ruf_ort = insert_ruf_ort,
                @insert_ruf_nummer = insert_ruf_nummer,
                @insert_ruf_durchwahl = insert_ruf_durchwahl,
                @insert_ruf_typ_anschluss = insert_ruf_typ_anschluss,
                @insert_ruf_typ_geraet = insert_ruf_typ_geraet,
                @insert_ruf_typ_outlook = insert_ruf_typ_outlook,
                @insert_ruf_quelle = insert_ruf_quelle,
                @insert_ruf_von = insert_ruf_von,
                @insert_ruf_fk_per = insert_ruf_fk_per,
                @insert_ruf_fk_adr = insert_ruf_fk_adr
        FROM    INSERTED

        IF        @insert_ruf_typ_outlook IS NOT NULL
--Zusätzliche Abfrage, die das Problem mit den NULL-Werten bisher scheinbar verhindert hat.
        AND (    SELECT    count(*)
                FROM    ruf
                WHERE    fk_unt = @pk
                AND (    fk_per = @insert_ruf_fk_per
                OR        fk_per IS NULL )
                AND        typ_outlook = @insert_ruf_typ_outlook
                AND (    ungueltig = 0
                OR        ungueltig IS NULL )
                AND (    bis > getdate()
                OR        bis IS NULL ) ) > 0
        BEGIN
                SET        @error =    'Im zugehörigen Outlook Kontakt ist bereits eine gültige Rufnummer als "' +
                                    @insert_ruf_typ_outlook + '" eingetragen.'
                RAISERROR(@error,16,1)
        END
        ELSE
                INSERT INTO    ruf(pk,fk_unt,land,ort,nummer,durchwahl,typ_anschluss,typ_geraet,
                            typ_outlook,quelle,von,fk_per,fk_adr)
                VALUES(    newid(),@pk,'0049',@insert_ruf_ort,@insert_ruf_nummer,@insert_ruf_durchwahl,
                        @insert_ruf_typ_anschluss,@insert_ruf_typ_geraet,@insert_ruf_typ_outlook,
                        @insert_ruf_quelle,@insert_ruf_von,@insert_ruf_fk_per,@insert_ruf_fk_adr)
                
                UPDATE    unt
                SET        insert_ruf_ort = NULL,
                        insert_ruf_nummer = NULL,
                        insert_ruf_durchwahl = NULL,
                        insert_ruf_typ_anschluss = NULL,
                        insert_ruf_typ_geraet = NULL,
                        insert_ruf_typ_outlook = NULL,
                        insert_ruf_quelle = NULL,
                        insert_ruf_von = NULL,
                        insert_ruf_fk_per = NULL,
                        insert_ruf_fk_adr = NULL
                WHERE    pk = @pk
END
GO

PHP:
CREATE TRIGGER    [dbo].[unt_insert_into_adr]
    ON            [dbo].[unt]
    AFTER UPDATE, INSERT
AS
IF        UPDATE(insert_adr_ort)
-- Komischer Fehler, Trigger auf UPDATE(insert_adr_ort) reagiert auf NULL,
-- daher Behelfslösung
AND (    SELECT    insert_adr_ort
        FROM    INSERTED ) IS NOT NULL
BEGIN
        SET NOCOUNT ON;

        DECLARE    @pk UNIQUEIDENTIFIER
        DECLARE    @insert_adr_strasse VARCHAR(40)
        DECLARE    @insert_adr_hausnr VARCHAR(8)
        DECLARE    @insert_adr_plz VARCHAR(8)
        DECLARE    @insert_adr_ort VARCHAR(40)
        DECLARE    @insert_adr_von DATETIME
        DECLARE    @insert_adr_typ VARCHAR(20)
        DECLARE    @insert_adr_quelle VARCHAR(20)
        DECLARE    @error VARCHAR(255)

        SELECT    @pk = pk,
                @insert_adr_strasse = insert_adr_strasse,
                @insert_adr_hausnr = insert_adr_hausnr,
                @insert_adr_plz = insert_adr_plz,
                @insert_adr_ort = insert_adr_ort,
                @insert_adr_von = insert_adr_von,
                @insert_adr_typ = insert_adr_typ,
                @insert_adr_quelle = insert_adr_quelle
        FROM    INSERTED

        IF (    SELECT    count(*)
                FROM    adr
                WHERE    fk_unt = @pk
                AND        typ = @insert_adr_typ
                AND (    quelle = @insert_adr_quelle
                OR        quelle IS NULL )
                AND (    ungueltig = 0
                OR        ungueltig IS NULL )
                AND (    bis > getdate()
                OR        bis IS NULL ) ) > 0
        BEGIN
                SET        @error =    'Es liegt Bereits eine derzeit gültige Adresse' +
                                    ( CASE WHEN @insert_adr_typ IS NOT NULL THEN ' Typ ' + @insert_adr_typ ELSE '' END ) +
                                    ( CASE WHEN @insert_adr_quelle IS NOT NULL THEN ' Quelle ' + @insert_adr_quelle ELSE '' END ) +
                                    ' vor. Bitte prüfen Sie die vorhandenen Unternehmensbezeichnungen.'
                RAISERROR (@error,16,1)
        END
        ELSE
                INSERT INTO    adr(pk,fk_unt,strasse,hausnr,plz,ort,von,typ,quelle)
                VALUES(    newid(),@pk,@insert_adr_strasse,@insert_adr_hausnr,@insert_adr_plz,
                        @insert_adr_ort,@insert_adr_von,@insert_adr_typ,@insert_adr_quelle)
                
                UPDATE    unt
                SET        insert_adr_strasse = NULL,
                        insert_adr_hausnr = NULL,
                        insert_adr_plz = NULL,
                        insert_adr_ort = NULL,
                        insert_adr_von = NULL,
                        insert_adr_typ = NULL,
                        insert_adr_quelle = NULL
                WHERE    pk = @pk
END
GO
 

ukulele

Datenbank-Guru
Beiträge
4.702
AW: Trigger mit UPDATE() Bedingung feuert bei NULL-Wert

[FONT=Verdana, Arial, Helvetica, sans-serif][FONT=Verdana, Arial, Helvetica, sans-serif]"One thing I haven't mentioned so far is the difference between a column being updated and a column being changed. An update occurs when you "set" a column to a value, even if it's the same value that already existed! I think many people mistake update triggers for "change" triggers. If you want to execute code only if something has changed, then you have to do the comparison in the where clause." so so...

Verzichte ich auf die UPDATE() Funktion und arbeite mit einer IF Abfrage auf einen Eintrag in der Spalte funktioniert das natürlich tadelos. Da aber 2 Trigger am Werk sind feuern diese rekursiv. Alles in einen AFTER Trigger zu bauen scheint eine Lösung, wird aber irgendwann unübersichtlich. Für Alternativen bin ich dankbar.[/FONT][/FONT]
 

ukulele

Datenbank-Guru
Beiträge
4.702
AW: Trigger mit UPDATE() Bedingung feuert bei NULL-Wert

Okay es ist nicht der Unterschied der beiden Trigger, es sind die Trigger der Zieltabellen die das ganze rekursiv feuern lassen. (Die Nebentabellen schreiben zurück in andere Spalten der Haupttabelle). :(

Ich debugge mal weiter...
 
Werbung:

Charly

Datenbank-Guru
Beiträge
306
AW: Trigger mit UPDATE() Bedingung feuert bei NULL-Wert

Hallo ukulele,

die Idee mit einem Trigger scheint mir in Anbetracht der Tatsache das beide Trigger auf der gleichen Tabelle sitzen durchaus sinnvoll.

Ich hab mich mal durch Deine Trigger gearbeitet.

Der ELSE Teil der inneren IF löst meiner Meinung auf jeden Fall den anderen Trigger aus (wegen dem Update auf unt). Dann schreibt Trigger B halt die NULL-Werte aus Deinem Update Befehl aus Trigger A in die Tabelle.

Alternativ könntest Du die Insert- und Update-Logik auch in Prozeduren packen. 4 Prozeduren (Jeweils eine pro Tabelle für UPDATE und INSERT). So was mache ich gerne.


Gruß Charly
 
Oben