如何在INSERT INTO表(等)SELECT * FROM Table2期间触发每个插入行的触发器?

时间:2011-04-27 14:06:02

标签: sql-server-2008 email triggers bulkinsert

我一直试图避免在这种特殊情况下使用游标只是因为我不喜欢权衡,而且我正在使用的过程恰好使得触发器看起来像是正确的行动方案。

存储过程根据复杂的子句组合插入记录,使用插入触发器向目标用户发送电子邮件,告诉他们访问站点。这很简单,工作正常。

但是,另一个程序是每晚运行并重新分发所有未查看的记录。我这样做的方式是根据分配时的日期字段上的选择进行另一次插入。即:

INSERT INTO Table (ID, User, AssignDate, LastActionDate)
    SELECT 
        ID
        ,User
        ,GETDATE() [AssignDate]
        ,GETDATE() [LastModifiedDate]
    FROM Table2
        /*snip*/

触发器适用于单个插入,但上面的select语句仅适用于最后插入的行。有办法绕过这种行为吗?它毁了整个事情!

编辑(触发代码):

ALTER TRIGGER dbo.Notify
    ON  dbo.Table
    AFTER INSERT
AS 
BEGIN

    DECLARE @EmailSender varchar(50)='Sender Profile'
    DECLARE @Identity int
    DECLARE @User varchar(20)
    DECLARE @Subject varchar(50)

    SET @Identity=@@Identity

    SELECT @User=User, @Subject='(' + CONVERT(varchar,@Identity) + ')!'
    FROM Table
    WHERE
        idNum=@Identity

    exec msdb.dbo.sp_send_dbmail
        @profile_name=@EmailSender,
        @recipients=@User
        @subject=@Subject,
        @body='//etc'

END

2 个答案:

答案 0 :(得分:10)

对于批量插入,会调用一次插入触发器,但在触发器上,您可以使用特殊的inserted表来获取所有插入的行。

所以,假设你有一个像这样的插入触发器,它会记录插入table的所有行

create trigger trgInsertTable 
on dbo.table
for insert
as
   insert tableLog(name)
    select name from inserted

使用此触发器,当您在table上进行批量插入时,tableLog将填充与插入table

相同的行数

对于特定的触发器,由于需要为每一行调用存储过程,因此需要使用游标:

ALTER TRIGGER dbo.Notify
    ON  dbo.Table
    AFTER INSERT
AS 
BEGIN

    DECLARE @EmailSender varchar(50)='Sender Profile'
    DECLARE @User varchar(20)
    DECLARE @Subject varchar(50)

    DECLARE cursor CURSOR FOR
      SELECT User, '(' + CONVERT(varchar, Id) + ')!'
        FROM inserted

    OPEN cursor
    FETCH NEXT FROM cursor INTO @User, @Subject
    WHILE @@FETCH_STATUS = 0
    BEGIN
      exec msdb.dbo.sp_send_dbmail
          @profile_name=@EmailSender,
          @recipients=@User
          @subject=@Subject,
          @body='//etc'
      FETCH NEXT FROM cursor INTO @User, @Subject
    END
    CLOSE cursor
    DEALLOCATE cursor

END

我没有测试,但应该工作

答案 1 :(得分:4)

如果您要发送电子邮件,我不会通过触发器执行此操作。你真的希望人们因电子邮件服务器关闭而无法插入记录吗?

通常最好将记录从触发器插入到表中,然后有一个作业发送每分钟左右运行的电子邮件,并将电子邮件状态更新为已发送,并在每个记录时将发送的日期时间添加到表中已发送。这不仅允许您在电子邮件关闭时插入记录,还可以移动循环以将每个单独的电子邮件发送到用户无法访问的表(因此任何延迟处理许多记录只会影响新用户而不是其他任何人)并且它允许您查看发送电子邮件的历史记录,这有助于人们质疑为什么他们没有得到它。如果电子邮件无法发送以帮助识别错误的电子邮件地址,您还可以在表格中记录。