2009-02-02 4 views
2

MS SQL Server не имеет триггеров уровня строки, правильно? Если мне нужно было вставить строку из триггера, а затем вставить другую строку, основанную на результате первой вставки, будет ли курсор лучшим решением?Альтернатива триггерам уровня строки?

Например, есть лучший способ сделать это:

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 

ответ

3

Я предполагаю, что вы на 2005 или лучше? Если это так, посмотрите в предложение OUTPUT, вам не нужны триггеры на уровне строк. Например:

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; 

Кроме того, можно управлять этим путем иметь триггер T1, который вставляет в T2, то триггер Т2, который вставляет в T3. Это не будет столь же эффективным ИМХО, и управлять им нелегко, но я буду заявлять, что его легче отслеживать (и может быть вашим единственным вариантом, если вы застряли в 2000 году). Оба могут быть настроены на основе набора и не нуждаются в курсорах или любом другом методе обработки строк за строкой.

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; 

(Кстати, если вы собираетесь для значений идентичности, использование scope_identity(), не @@ IDENTITY.)

+0

Спасибо, мне очень нравится ваше решение с OUTPUT! – Alvis

1

Почему не каскад триггеров - Использовать триггер INSERT на Т2 выполнить вставку на T3. После этого вы можете избежать курсор внутри t1_insert_trg и просто использовать вставленный - как в:

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

Вы можете быть в состоянии избежать курсора или необходимость знать, что идентичность была вставлена используя следующие вставки.

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 
Смежные вопросы