如何从触发器内部的其他表中获取插入的ID?

时间:2017-02-16 13:25:04

标签: sql sql-server triggers

我有3个表tbl_Userstbl_Protocoltbl_ProtocolDetails,并且在Users的触发器内,我必须插入Protocol然后插入ProtocolDetails,但我不知道插入范围的工作原理。

类似的东西:

CREATE TRIGGER tg_Users ON tbl_Users 
AFTER INSERT, UPDATE AS
BEGIN
    DECLARE @UserId     = Int
    DECLARE @ProtocolId = Int
    DECLARE @UserDetail = NVARCHAR(255)

    SELECT 
         @UserId = user_id,
         @UserDetail = user_detail + '@' + user_explanation
    FROM INSERTED

    INSERT INTO tbl_Protocol (user_id, inserted_date) 
    VALUES (@UserId, GetDate()) 

    -- Return Inserted Id from tbl_Protocol into @ProtocolDetail then

    INSERT INTO tbl_ProtocolDetails (protocol_id, protocol_details) 
    VALUES (@ProtocolId, @UserDetail) 
END

2 个答案:

答案 0 :(得分:2)

您的触发器有一个 MAJOR 缺陷,因为您似乎总是在Inserted表中只有一行 - 的情况,因为触发器将被称为每个语句一次(每行不会一次),所以如果一次插入20行,则触发器只被称为一次,并且Inserted伪表包含20行。

因此,代码如下:

Select  @UserId = user_id,
        @UserDetail = user_detail + '@' + user_explanation
From    INSERTED;

失败,因为您只会从Inserted表中检索一个(任意)行,并且您将忽略所有其他行在Inserted

编程扳机时需要考虑到这一点!你必须以适当的,强烈的,基于集合的方式做到这一点 - 而不是一行一阵地捣乱!

试试这段代码:

CREATE TRIGGER tg_Users ON tbl_Users 
AFTER INSERT, UPDATE AS
BEGIN
    -- declare an internal table variable to hold the inserted "ProtocolId" values
    DECLARE @IdTable TABLE (UserId INT, ProtocolId INT);

    -- insert into the "tbl_Protocol" table from the "Inserted" pseudo table
    -- keep track of the inserted new ID values in the @IdTable
    INSERT INTO tbl_Protocol (user_id, inserted_date) 
        OUTPUT Inserted.user_id, Inserted.ProtocolId INTO @IdTable(UserId, ProtocolId)
        SELECT user_id, SYSDATETIME()
        FROM Inserted;

    -- insert into the "tbl_ProtocolDetails" table from both the @IdTable,
    -- as well as the "Inserted" pseudo table, to get all the necessary values
    INSERT INTO tbl_ProtocolDetails (protocol_id, protocol_details) 
        SELECT 
            t.ProtocolId, 
            i.user_detail + '@' + i.user_explanation
        FROM 
            @IdTable t
        INNER JOIN 
            Inserted i ON i.user_id = t.UserId
END

答案 1 :(得分:0)

此触发器中没有任何内容可以处理多个插入/更新语句。您将需要使用一个将处理多个记录的方案,或使用IF @@ ROWCOUNT = 1 else语句检查有多少记录受影响。在你的例子中,我会使用像

这样的东西
insert into tbl_Protocol(user_id, inserted_date)
select user_id, user_detail + '@' + user_explanation
From    INSERTED;

至于你的详细信息表,我看到Marc纠正了他的答案,包括多行并有一个简单的解决方案,或者你可以在tbl_Protocol上创建第二个触发器。我过去使用的另一个解决方案是在我有非常复杂的触发器时进行处理的临时表。