Альтернатива триггерам уровня строки? - PullRequest
2 голосов
/ 02 февраля 2009

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 ]

3 голосов
/ 02 февраля 2009

Я полагаю, вы на 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;

Вы также можете управлять этим, имея триггер на Т1, который вставляется в Т2, а затем триггер на Т2, который вставляется в Т3. Это не будет столь же эффективным, как имхо, и им будет не легко управлять, но я утверждаю, что за ним легче следовать (и, возможно, это ваш единственный вариант, если вы застряли на 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.)

2 голосов
/ 02 февраля 2009

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

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
1 голос
/ 02 февраля 2009

Почему бы не каскадировать триггеры - используйте триггер INSERT на T2, чтобы выполнить вставку на 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...