【发布时间】:2013-11-01 22:55:19
【问题描述】:
我在 Microsoft SQL Server 中创建了一个更新触发器,如果日期连续更改,它会向我发送电子邮件。
与此类似:
IF UPDATE(ColumnName)
BEGIN
DECLARE @columnVal AS DATETIME
SELECT
@columnVal = i.columnName
FROM
inserted i JOIN deleted d on i.RowId= d.RowId;
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'me',
@recipients = 'me@company.com',
@body = 'blah blah datechange',
@body_format = 'HTML',
@subject = 'subject';
END
它工作了一段时间。
然后我切换到批量更新,如果多行的日期发生变化,则只发送第一行电子邮件。我试图设置一个光标来滚动更改,但我无法让它工作,类似于下面:
DECLARE @columnVal AS DATETIME
DECLARE cur CURSOR LOCAL READ_ONLY FAST_FORWARD FOR
SELECT
i.ColumnName
FROM
inserted i JOIN deleted d on i.RowId= d.RowId;
OPEN cur
FETCH NEXT FROM cur INTO @columnVal
WHILE @@FETCH_STATUS = 0
BEGIN
IF UPDATE(ColumnName)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'me',
@recipients = 'me@company.com',
@body = 'blah blah datechange',
@body_format = 'HTML',
@subject = 'subject';
END
FETCH NEXT FROM cur INTO @columnVal
END
CLOSE cur
DEALLOCATE cur
关于如何完成这项任务的任何想法? Update(ColumnName) 函数甚至可以在游标内正常工作(它实际上会告诉我该列是否已针对该行进行了更新吗?)
【问题讨论】:
-
trigger 中的 cursor 是一个非常非常糟糕的主意。触发器应该非常精简 - 它不应该做很多工作!我建议只“记下”您必须向谁发送电子邮件 - 但将电子邮件的实际发送留给单独的例如SQL Server 代理作业,它不是触发器的一部分。触发器经常被触发并且经常出乎意料 - 不要将处理负担放入其中!尤其是不像光标这样的性能杀手!
-
UPDATE() 函数在行基础上不起作用。它返回该列是否更新的任何内容,因此对于您的所有行,它将为真(或假)。您应该为每一行检查自己的任何
i.ColumnName <> d.ColumnName。 +@marc_s 所说的一切! -
@NetDev 使用
WHERE子句!但是,如果您确实想为从 true 更新为 true 的行发送电子邮件,您不需要任何过滤吗?inserted和deleted表中的所有行都是受更新影响的行。不多也不少。我认为您的IF UPDATE()背后的整个想法是只过滤实际更改的行。 -
是的,必须在该列中,您不能运行单个更新来更新不同行中的不同列。如果
UPDATE(ColumnName)为真,这意味着inserted中的每一行都更新了该列 - 可能具有相同的现有值,但它已更新。 -
对于
WHERE子句,您只需将条件应用于inserted和deleted表。例如,如果您想记录某些列中实际更改的行并将它们保存在某个 tempMail 表中,您可以使用INSERT INTO tempMail SELECT i.* FROM inserted i INNER JOIN deleted d ON i.ID = d.ID WHERE i.SomeColumn <> d.SomeColumn
标签: sql sql-server tsql triggers sql-update