有一个定期运行并从表中提取存储过程参数的 SQL 代理作业 - 这些行还应指示存储过程的运行时间,因此 SQL 代理作业将仅选择到期/稍微逾期的行。它应该在调用存储过程后删除行或标记它们。
然后,在触发器中,只需将新行插入同一个表中。
You do not想要将任何内容放入触发器中,从而以任何方式影响原始事务的执行 - 您绝对不希望造成任何延迟,或与同一数据库之外的任何内容进行交互。
例如,如果存储过程是
CREATE PROCEDURE DoMagic
@Name varchar(20),
@Thing int
AS
...
然后我们创建一个表:
CREATE TABLE MagicDue (
MagicID int IDENTITY(1,1) not null, --May not be needed if other columns uniquely identify
Name varchar(20) not null,
Thing int not null,
DoMagicAt datetime not null
)
SQL 代理作业将执行以下操作:
WHILE EXISTS(SELECT * from MagicDue where DoMagicAt < CURRENT_TIMESTAMP)
BEGIN
DECLARE @Name varchar(20)
DECLARE @Thing int
DECLARE @MagicID int
SELECT TOP 1 @Name = Name,@Thing = Thing,@MagicID = MagicID from MagicDue where DoMagicAt < CURRENT_TIMESTAMP
EXEC DoMagic @Name,@Thing
DELETE FROM MagicDue where MagicID = @MagicID
END
触发器只会有:
CREATE TRIGGER Xyz ON TabY after insert
AS
/*Do stuff, maybe calculate some values, or just a direct insert?*/
insert into MagicDue (Name,Thing,DoMagicAt)
select YName,YThing+1,DATEADD(minute,30,CURRENT_TIMESTAMP) from inserted
如果您运行的版本不支持代理,那么您可能必须伪造它。我过去所做的是创建一个包含“穷人代理作业”的存储过程,如下所示:
CREATE PROCEDURE DoBackgroundTask
AS
WHILE 1=1
BEGIN
/* Add whatever SQL you would have put in an agent job here */
WAITFOR DELAY '00:05:00'
END
然后,创建第二个存储过程,这次是在master
数据库,等待 30 秒,然后调用第一个过程:
CREATE PROCEDURE BootstrapBackgroundTask
AS
WAITFOR DELAY '00:00:30'
EXEC YourDB..DoBackgroundTask
然后,将此过程标记为启动过程,使用sp_procoption:
EXEC sp_procoption N'BootstrapBackgroundTask', 'startup', 'on'
并重新启动服务 - 您现在将有一个连续运行的查询。