2009-02-02 8 views
2

MS SQL Server n'a pas de déclencheurs de niveau ligne, correct? Si j'avais besoin d'insérer une ligne à l'intérieur d'un trigger puis d'insérer une autre ligne, en fonction du résultat du premier insert, un curseur serait-il la meilleure solution?Alternative aux déclencheurs de niveau ligne?

Par exemple, est-il une meilleure façon de le faire:

CREATE TABLE t1 (foo int) 
CREATE TABLE t2 (id int IDENTITY, foo int) 
CREATE TABLE t3 (t2_id int) 

GO 

CREATE TRIGGER t1_insert_trg ON t1 FOR INSERT AS 
    DECLARE c CURSOR FOR 
     SELECT foo FROM inserted 
    DECLARE @foo int 
    OPEN c 
    FETCH NEXT FROM c INTO @foo 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     INSERT INTO t2 (foo) VALUES (@foo) 
     INSERT INTO t3 (t2_id) VALUES (@@IDENTITY) 
     FETCH NEXT FROM c INTO @foo 
    END 
    CLOSE c 
    DEALLOCATE c 

Répondre

3

Je suppose que vous êtes en 2005 ou mieux? Si oui, regardez dans la clause OUTPUT, vous ne devriez pas avoir besoin de triggers au niveau de la ligne. Par exemple:

USE tempdb; 
GO 

CREATE TABLE t1 (foo int); 
CREATE TABLE t2 (id int IDENTITY, foo int); 
CREATE TABLE t3 (t2_id int); 
GO 

CREATE TRIGGER t1_insert ON t1 
FOR INSERT AS 
BEGIN 
    DECLARE @new_rows TABLE(new_id INT, old_foo INT); 

    INSERT t2(foo) 
     OUTPUT inserted.id, inserted.foo 
     INTO @new_rows 
    SELECT foo 
    FROM inserted; 

    INSERT t3 SELECT new_id FROM @new_rows; 
END 
GO 

INSERT t1(foo) SELECT 1 UNION ALL SELECT 5; 
SELECT * FROM t1; 
SELECT * FROM t2; 
SELECT * FROM t3; 
GO 

DROP TABLE t1,t2,t3; 

Vous pouvez également gérer cela en ayant un déclencheur sur T1 qui insère dans T2, puis un déclencheur sur T2 qui insère dans T3. Cela ne va pas être aussi efficace à mon humble avis, et n'est pas plus facile à gérer, mais je vais dire qu'il est plus facile à suivre (et peut-être votre seule option si vous êtes bloqué sur 2000). Les deux pourraient être basés sur des ensembles et n'auraient pas besoin de curseurs ni d'autres méthodes de traitement ligne par ligne.

USE tempdb; 
GO 

CREATE TABLE t1 (foo int); 
CREATE TABLE t2 (id int IDENTITY, foo int); 
CREATE TABLE t3 (t2_id int); 
GO 

CREATE TRIGGER t1_insert ON t1 
FOR INSERT AS 
BEGIN  
    INSERT t2(foo) 
    SELECT foo FROM inserted; 
END 
GO 

CREATE TRIGGER t2_insert ON t2 
FOR INSERT AS 
BEGIN 
    INSERT t3(t2_id) 
    SELECT id FROM inserted; 
END 
GO 

INSERT t1(foo) SELECT 1 UNION ALL SELECT 5; 
SELECT * FROM t1; 
SELECT * FROM t2; 
SELECT * FROM t3; 
GO 

DROP TABLE t1,t2,t3; 

(BTW, si vous allez pour les valeurs d'identité, l'utilisation SCOPE_IDENTITY(), non @@ IDENTITY.)

+0

Merci, j'aime beaucoup votre solution avec OUTPUT! – Alvis

1

Pourquoi ne pas en cascade les déclencheurs - Utilisez un déclencheur INSERT sur T2 pour réaliser l'insert sur T3. Ensuite, vous pouvez éviter le curseur dans t1_insert_trg et il suffit d'utiliser inséré - comme dans:

CREATE TRIGGER t1_insert_trg ON t1 FOR INSERT AS 
    INSERT INTO t2 
    SELECT foo FROM inserted -- fires t2 INSERTED trigger 

CREATE TRIGGER t2_insert_trg ON t2 FOR INSERT AS 
    INSERT INTO t3 
    SELECT id FROM inserted 
2

Vous pourriez être en mesure d'éviter un curseur ou le besoin de savoir ce que l'identité a été inséré en utilisant les inserts suivants.

Insert INTO t2 (foo) Select foo from inserted 
Insert into t3 (t2_id) Select t2.id from t2 
inner join inserted i on t2.foo = i.foo 
Questions connexes