none
Trigger- Daten in eine Tabelle eingeben RRS feed

  • Frage

  • Hallo Liebe Leute,

    könnt ihr mir sagen, was an diesem Trigger nicht stimmt?


    if (OBJECT_ID ('t_reich_arm', 'T')) is not null
    drop trigger t_reich_arm
    go

    create trigger t_reich_arm on personal
    after insert
    as

    Declare @geld int
    set @geld = (select verdienst from inserted)
    IF @geld >= 2500

    insert into reich (vorname, verdienst)
    select I.vorname, I.verdienst
    from inserted I

    else
    insert into arm (vorname, verdienst)
    select I.vorname, I.verdienst
    from inserted I

    Wenn ich die Daten in die Tabelle Personal eingebe, dann sehe ich ordnungsgemäß alle Daten. In den Tabellen reich und arm sind keine Daten vorhanden. Die Abfrage wird auch fehlerlos abgeschlossen.

    Was habe ich bei dem Trigger falsch gemacht.

    Viele Grüsse:

    Arek


    Arek

    Mittwoch, 11. Juni 2014 07:46

Antworten

  • Hallo Arek,

    grundsätzlich funktioniert es, es sind aber die typischen Basic-Fehler enthalten.

    1. Objekt Kürzel von Triggern ist TR, nicht einfach nur T =>

    if (OBJECT_ID ('t_reich_arm', 'TR')) is not null

    2. Ein Trigger feuert je Transaktion, nicht je Datensatz, Dein Trigger geht aber davon aus, das es nur einen Datensatz gibt. Es könnte sein, das 2 Datensätze mit einmal Verdienst < 2500 und einmal mit > 2500 eingefügt wird; dann macht Dein Trigger irgendwas, nur nicht gerade das gewünschte.

    Leg mal eine neue Testdatenbank an und probiere dort mal folgendes Skript aus:

    CREATE TABLE dbo.personal (vorname varchar(30), verdienst int);
    CREATE TABLE dbo.reich (vorname varchar(30), verdienst int);
    CREATE TABLE dbo.arm (vorname varchar(30), verdienst int);
    GO
    
    create trigger t_reich_arm on dbo.personal
     after insert
     as
    
     Declare @geld int
     set @geld = (select verdienst from inserted)
     IF @geld >= 2500 
    
     insert into reich (vorname, verdienst)
     select I.vorname, I.verdienst
     from inserted I
    
     else 
     insert into arm (vorname, verdienst)
     select I.vorname, I.verdienst
     from inserted I
    
    GO
    
    INSERT INTO dbo.personal (vorname, verdienst) VALUES ('Olaf', 1234);
    GO
    
    SELECT * FROM dbo.personal;
    SELECT * FROM dbo.arm;
    SELECT * FROM dbo.reich;
    GO
    
    -- Mulit Insert
    INSERT INTO dbo.personal (vorname, verdienst) 
    VALUES ('Peter', 2345), ('Maria', 3333);
    GO
    
    SELECT * FROM dbo.personal;
    SELECT * FROM dbo.arm;
    SELECT * FROM dbo.reich;
    


    Übrigens, ist in Deiner Tabelle "Verdienst" ein Integer Wert, wie im Trigger, oder doch eher ein Dezimal/Money Typ?


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    Mittwoch, 11. Juni 2014 08:41
  • Hallo Arek,

    neben der von Olaf gegebenen Antwort:

    Ein Trigger ist eigentlich überflüssig, denn das gleich könnten zwei Sichten leisten:

    CREATE VIEW dbo.Personal_Reich
    AS
    	SELECT Vorname, Verdienst 
    	FROM dbo.Personal 
    	WHERE Verdienst >= 2500.0;
    GO
    CREATE VIEW dbo.Personal_Arm
    AS
    	SELECT Vorname, Verdienst 
    	FROM dbo.Personal 
    	WHERE Verdienst < 2500.0;
    GO

    dann gibt es auch kein Problem, wenn sich die Verdienst mal ändern.

    Deswegen nur der Vollständigkeit halber eine Variante, die auf MERGE setzt, und Probleme mit mehreren Zeilen bzw. Veränderungen vermeidet:

    CREATE TABLE dbo.Personal (
        Vorname varchar(20) NOT NULL,
        Verdienst decimal(10, 2) NOT NULL);
        
    CREATE TABLE dbo.Arm(
        Vorname varchar(20),
        Verdienst decimal(10, 2));
        
    CREATE TABLE dbo.Reich(
        Vorname varchar(20), 
        Verdienst decimal(10, 2));
    GO
    
    CREATE TRIGGER dbo.TR_Personal_Insert
        ON dbo.Personal
        AFTER INSERT, UPDATE
    AS
        SET NOCOUNT ON;
    
        MERGE dbo.Reich AS target
        USING (SELECT Vorname, Verdienst FROM inserted) AS source(Vorname, Verdienst)
            ON target.Vorname = source.Vorname
        -- War vorhanden, jedoch zu wenig
        WHEN MATCHED AND source.Verdienst < 2500.0
            THEN DELETE
        WHEN MATCHED AND source.Verdienst >= 2500.0
            THEN UPDATE SET Verdienst = source.Verdienst
        WHEN NOT MATCHED AND source.Verdienst >= 2500.0
            THEN INSERT (Vorname, Verdienst)
                VALUES (source.Vorname, source.Verdienst);
    
        MERGE dbo.Arm AS target
        USING (SELECT Vorname, Verdienst FROM inserted) AS source(Vorname, Verdienst)
            ON target.Vorname = source.Vorname
        -- War vorhanden, jedoch zu wenig
        WHEN MATCHED AND source.Verdienst >= 2500.0
            THEN DELETE
        WHEN MATCHED AND source.Verdienst < 2500.0
            THEN UPDATE SET Verdienst = source.Verdienst
        WHEN NOT MATCHED AND source.Verdienst < 2500.0
            THEN INSERT (Vorname, Verdienst)
                VALUES (source.Vorname, source.Verdienst);
    GO
    
    INSERT INTO Personal (Vorname, Verdienst)
    VALUES ('Alfred', 1000),
            ('Bernhard', 2500),
            ('Cäsar', 2000),
            ('Detlef', 2499.99),
            ('Egon', 3000);
            
    SELECT 'Arm:', * FROM Arm;
    SELECT 'Reich:', * FROM Reich;
    
    UPDATE Personal 
    SET Verdienst = CASE WHEN Verdienst > 2500.0
        THEN Verdienst - 100.0
        ELSE Verdienst + 100.0 END;
    
    SELECT 'Nun Arm:', * FROM Arm;
    SELECT 'Nun Reich:', * FROM Reich;
    GO
    

    Den DELETE Trigger habe ich mal weggelassen, der sollte kein Kunststück sein ;)

    Sinnvoller wäre im übrigen eine ID, denn Namen können sich ändern.

    Gruß Elmar

    Mittwoch, 11. Juni 2014 08:52
    Beantworter

Alle Antworten

  • Hallo Arek,

    grundsätzlich funktioniert es, es sind aber die typischen Basic-Fehler enthalten.

    1. Objekt Kürzel von Triggern ist TR, nicht einfach nur T =>

    if (OBJECT_ID ('t_reich_arm', 'TR')) is not null

    2. Ein Trigger feuert je Transaktion, nicht je Datensatz, Dein Trigger geht aber davon aus, das es nur einen Datensatz gibt. Es könnte sein, das 2 Datensätze mit einmal Verdienst < 2500 und einmal mit > 2500 eingefügt wird; dann macht Dein Trigger irgendwas, nur nicht gerade das gewünschte.

    Leg mal eine neue Testdatenbank an und probiere dort mal folgendes Skript aus:

    CREATE TABLE dbo.personal (vorname varchar(30), verdienst int);
    CREATE TABLE dbo.reich (vorname varchar(30), verdienst int);
    CREATE TABLE dbo.arm (vorname varchar(30), verdienst int);
    GO
    
    create trigger t_reich_arm on dbo.personal
     after insert
     as
    
     Declare @geld int
     set @geld = (select verdienst from inserted)
     IF @geld >= 2500 
    
     insert into reich (vorname, verdienst)
     select I.vorname, I.verdienst
     from inserted I
    
     else 
     insert into arm (vorname, verdienst)
     select I.vorname, I.verdienst
     from inserted I
    
    GO
    
    INSERT INTO dbo.personal (vorname, verdienst) VALUES ('Olaf', 1234);
    GO
    
    SELECT * FROM dbo.personal;
    SELECT * FROM dbo.arm;
    SELECT * FROM dbo.reich;
    GO
    
    -- Mulit Insert
    INSERT INTO dbo.personal (vorname, verdienst) 
    VALUES ('Peter', 2345), ('Maria', 3333);
    GO
    
    SELECT * FROM dbo.personal;
    SELECT * FROM dbo.arm;
    SELECT * FROM dbo.reich;
    


    Übrigens, ist in Deiner Tabelle "Verdienst" ein Integer Wert, wie im Trigger, oder doch eher ein Dezimal/Money Typ?


    Olaf Helper

    [ Blog] [ Xing] [ MVP]

    Mittwoch, 11. Juni 2014 08:41
  • Hallo Arek,

    neben der von Olaf gegebenen Antwort:

    Ein Trigger ist eigentlich überflüssig, denn das gleich könnten zwei Sichten leisten:

    CREATE VIEW dbo.Personal_Reich
    AS
    	SELECT Vorname, Verdienst 
    	FROM dbo.Personal 
    	WHERE Verdienst >= 2500.0;
    GO
    CREATE VIEW dbo.Personal_Arm
    AS
    	SELECT Vorname, Verdienst 
    	FROM dbo.Personal 
    	WHERE Verdienst < 2500.0;
    GO

    dann gibt es auch kein Problem, wenn sich die Verdienst mal ändern.

    Deswegen nur der Vollständigkeit halber eine Variante, die auf MERGE setzt, und Probleme mit mehreren Zeilen bzw. Veränderungen vermeidet:

    CREATE TABLE dbo.Personal (
        Vorname varchar(20) NOT NULL,
        Verdienst decimal(10, 2) NOT NULL);
        
    CREATE TABLE dbo.Arm(
        Vorname varchar(20),
        Verdienst decimal(10, 2));
        
    CREATE TABLE dbo.Reich(
        Vorname varchar(20), 
        Verdienst decimal(10, 2));
    GO
    
    CREATE TRIGGER dbo.TR_Personal_Insert
        ON dbo.Personal
        AFTER INSERT, UPDATE
    AS
        SET NOCOUNT ON;
    
        MERGE dbo.Reich AS target
        USING (SELECT Vorname, Verdienst FROM inserted) AS source(Vorname, Verdienst)
            ON target.Vorname = source.Vorname
        -- War vorhanden, jedoch zu wenig
        WHEN MATCHED AND source.Verdienst < 2500.0
            THEN DELETE
        WHEN MATCHED AND source.Verdienst >= 2500.0
            THEN UPDATE SET Verdienst = source.Verdienst
        WHEN NOT MATCHED AND source.Verdienst >= 2500.0
            THEN INSERT (Vorname, Verdienst)
                VALUES (source.Vorname, source.Verdienst);
    
        MERGE dbo.Arm AS target
        USING (SELECT Vorname, Verdienst FROM inserted) AS source(Vorname, Verdienst)
            ON target.Vorname = source.Vorname
        -- War vorhanden, jedoch zu wenig
        WHEN MATCHED AND source.Verdienst >= 2500.0
            THEN DELETE
        WHEN MATCHED AND source.Verdienst < 2500.0
            THEN UPDATE SET Verdienst = source.Verdienst
        WHEN NOT MATCHED AND source.Verdienst < 2500.0
            THEN INSERT (Vorname, Verdienst)
                VALUES (source.Vorname, source.Verdienst);
    GO
    
    INSERT INTO Personal (Vorname, Verdienst)
    VALUES ('Alfred', 1000),
            ('Bernhard', 2500),
            ('Cäsar', 2000),
            ('Detlef', 2499.99),
            ('Egon', 3000);
            
    SELECT 'Arm:', * FROM Arm;
    SELECT 'Reich:', * FROM Reich;
    
    UPDATE Personal 
    SET Verdienst = CASE WHEN Verdienst > 2500.0
        THEN Verdienst - 100.0
        ELSE Verdienst + 100.0 END;
    
    SELECT 'Nun Arm:', * FROM Arm;
    SELECT 'Nun Reich:', * FROM Reich;
    GO
    

    Den DELETE Trigger habe ich mal weggelassen, der sollte kein Kunststück sein ;)

    Sinnvoller wäre im übrigen eine ID, denn Namen können sich ändern.

    Gruß Elmar

    Mittwoch, 11. Juni 2014 08:52
    Beantworter