Sql 创建状态更新触发器
我有两张这样的桌子: 作业表格Sql 创建状态更新触发器,sql,sql-server,sql-server-2005,triggers,Sql,Sql Server,Sql Server 2005,Triggers,我有两张这样的桌子: 作业表格 Jobcode UserId Status 101 130 R 102 139 D UserId Email 130 test@example.com 用户表格 Jobcode UserId Status 101 130 R 102 139 D UserId Email 130 test@exam
Jobcode UserId Status
101 130 R
102 139 D
UserId Email
130 test@example.com
用户表格
Jobcode UserId Status
101 130 R
102 139 D
UserId Email
130 test@example.com
我想在插入和更新时创建一个触发器,向我的存储过程发送电子邮件:
EXEC dbo.SendMyEmail @email, @jobcode;
当作业代码作为“D”插入或更新为“D”时。我不确定数据类型等,但这至少会让您走上正确的轨道。 希望对你有帮助
CREATE TRIGGER SendEmailOnStatusD
ON JOBS
-- trigger is fired when an update is made for the table
FOR UPDATE --You can add the same for INSERT
AS
-- holds the UserID so we know which Customer was updated
DECLARE @UserID int
DECLARE @JobCode int
SELECT @UserID = UserId, @JobCode = JobCode
FROM INSERTED WHERE [Status] = 'D' --If you want the old value before the update, use 'deleted' table instead of 'inserted' table
IF (@UserID IS NOT NULL)
BEGIN
-- holds the email
DECLARE @email varchar(250)
SELECT @email = Email FROM USERS WHERE UserId = @UserID
EXEC SendMyEmail (@email, @jobcode);
END
GO
编辑:
上面的代码不处理多个更新,所以要获得更好的实践,请参阅下面的选项
CREATE TRIGGER SendEmailOnStatusD ON JOBS
-- trigger is fired when an update is made for the table
FOR UPDATE --You can add the same for INSERT
AS
DECLARE @Updates table(UserID int, JobCode int, Email varchar(250))
INSERT INTO @Updates (UserID, JobCode, Email)
SELECT i.UserID, i.JobCode, u.Email
FROM INSERTED i
JOIN USERS u ON i.UserID = u.UserID
WHERE [Status] = 'D'
DECLARE @UserID int
DECLARE @JobCode int
DECLARE @Email varchar(250)
WHILE EXISTS(SELECT * FROM @Updates)
BEGIN
SELECT TOP 1
@UserID = UserID,
@Email = Email,
@JobCode = JobCode
FROM @Updates WHERE UserID = @UserID
EXEC SendMyEmail (@email, @jobcode);
DELETE FROM @Updates
WHERE UserID = @UserID
END
GO
此外,正如在评论中所讨论的,从触发器发送电子邮件也不是最好的,但由于这是问题所要求的,因此已包括在内。我会推荐发送电子邮件的其他选项,如其他答案中提到的队列。我不确定数据类型等,但这至少会让您走上正确的道路。 希望对你有帮助
CREATE TRIGGER SendEmailOnStatusD
ON JOBS
-- trigger is fired when an update is made for the table
FOR UPDATE --You can add the same for INSERT
AS
-- holds the UserID so we know which Customer was updated
DECLARE @UserID int
DECLARE @JobCode int
SELECT @UserID = UserId, @JobCode = JobCode
FROM INSERTED WHERE [Status] = 'D' --If you want the old value before the update, use 'deleted' table instead of 'inserted' table
IF (@UserID IS NOT NULL)
BEGIN
-- holds the email
DECLARE @email varchar(250)
SELECT @email = Email FROM USERS WHERE UserId = @UserID
EXEC SendMyEmail (@email, @jobcode);
END
GO
编辑:
上面的代码不处理多个更新,所以要获得更好的实践,请参阅下面的选项
CREATE TRIGGER SendEmailOnStatusD ON JOBS
-- trigger is fired when an update is made for the table
FOR UPDATE --You can add the same for INSERT
AS
DECLARE @Updates table(UserID int, JobCode int, Email varchar(250))
INSERT INTO @Updates (UserID, JobCode, Email)
SELECT i.UserID, i.JobCode, u.Email
FROM INSERTED i
JOIN USERS u ON i.UserID = u.UserID
WHERE [Status] = 'D'
DECLARE @UserID int
DECLARE @JobCode int
DECLARE @Email varchar(250)
WHILE EXISTS(SELECT * FROM @Updates)
BEGIN
SELECT TOP 1
@UserID = UserID,
@Email = Email,
@JobCode = JobCode
FROM @Updates WHERE UserID = @UserID
EXEC SendMyEmail (@email, @jobcode);
DELETE FROM @Updates
WHERE UserID = @UserID
END
GO
此外,正如在评论中所讨论的,从触发器发送电子邮件也不是最好的,但由于这是问题所要求的,因此已包括在内。我会推荐其他发送电子邮件的选项,如其他答案中提到的队列。在我看来,使用触发器发送电子邮件不是最佳选择 相反,您应该只插入一个队列表,并让一个进程经常运行,检查该表并发送电子邮件 如果您的电子邮件过程中出现错误,会发生什么情况?它将强制回滚作业完成状态。只有你知道这是轻微的还是灾难性的。但我可以肯定地告诉您,DB的最佳实践是在DML操作期间不进行扩展I/O
CREATE TRIGGER TR_Jobs_EnqueueEmail_IU ON dbo.Jobs FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
INSERT dbo.EmailQueue (UserID, JobCode)
SELECT UserID, JobCode
FROM
Inserted I
LEFT JOIN Deleted D
ON I.JobCode = D.JobCode -- or proper PK columns
WHERE
IsNull(D.Status, 'R') <> 'D'
AND I.Status = 'D';
然后,从SQL作业每分钟运行一次以下存储过程:
CREATE PROCEDURE dbo.EmailProcess
AS
DECLARE @Email TABLE (
QueuedDate datetime,
UserID int,
JobCode int
);
DECLARE
@EmailAddress nvarchar(255),
@JobCode int;
WHILE 1 = 1 BEGIN
DELETE TOP 1 Q.*
OUTPUT Inserted.QueuedDate, Inserted.UserID, Inserted.JobCode
INTO @Email (QueuedDate, UserID, JobCode)
FROM dbo.EmailQueue Q WITH (UPDLOCK, ROWLOCK, READPAST)
ORDER BY QueuedDate;
IF @@RowCount = 0 RETURN;
SELECT @EmailAddress = U.EmailAddress, @JobCode = E.JobCode
FROM
@Email E
INNER JOIN dbo.User U
ON E.UserID = U.UserID;
EXEC dbo.SendMyEmail @EmailAddress, @JobCode;
DELETE E
OUTPUT QueuedDate, UserID, JobCode
INTO dbo.EmailSent (QueuedDate, UserID, JobCode)
FROM @Email E;
END;
我使用的删除模式和锁是经过特别选择的。如果您更改它们或以任何方式更改删除模式,几乎可以肯定您将破坏它。处理锁和并发是很困难的。不要改变它
注意:我没有在SQL Server上检查任何内容就键入了上述所有内容。很可能有打字错误。请原谅任何错误。在我看来,用触发器发送电子邮件并非最佳选择 相反,您应该只插入一个队列表,并让一个进程经常运行,检查该表并发送电子邮件 如果您的电子邮件过程中出现错误,会发生什么情况?它将强制回滚作业完成状态。只有你知道这是轻微的还是灾难性的。但我可以肯定地告诉您,DB的最佳实践是在DML操作期间不进行扩展I/O
CREATE TRIGGER TR_Jobs_EnqueueEmail_IU ON dbo.Jobs FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
INSERT dbo.EmailQueue (UserID, JobCode)
SELECT UserID, JobCode
FROM
Inserted I
LEFT JOIN Deleted D
ON I.JobCode = D.JobCode -- or proper PK columns
WHERE
IsNull(D.Status, 'R') <> 'D'
AND I.Status = 'D';
然后,从SQL作业每分钟运行一次以下存储过程:
CREATE PROCEDURE dbo.EmailProcess
AS
DECLARE @Email TABLE (
QueuedDate datetime,
UserID int,
JobCode int
);
DECLARE
@EmailAddress nvarchar(255),
@JobCode int;
WHILE 1 = 1 BEGIN
DELETE TOP 1 Q.*
OUTPUT Inserted.QueuedDate, Inserted.UserID, Inserted.JobCode
INTO @Email (QueuedDate, UserID, JobCode)
FROM dbo.EmailQueue Q WITH (UPDLOCK, ROWLOCK, READPAST)
ORDER BY QueuedDate;
IF @@RowCount = 0 RETURN;
SELECT @EmailAddress = U.EmailAddress, @JobCode = E.JobCode
FROM
@Email E
INNER JOIN dbo.User U
ON E.UserID = U.UserID;
EXEC dbo.SendMyEmail @EmailAddress, @JobCode;
DELETE E
OUTPUT QueuedDate, UserID, JobCode
INTO dbo.EmailSent (QueuedDate, UserID, JobCode)
FROM @Email E;
END;
我使用的删除模式和锁是经过特别选择的。如果您更改它们或以任何方式更改删除模式,几乎可以肯定您将破坏它。处理锁和并发是很困难的。不要改变它
注意:我没有在SQL Server上检查任何内容就键入了上述所有内容。很可能有打字错误。请原谅任何错误。我不得不批评一个触发器无法同时处理多行插入的答案。很抱歉。这不是最佳做法。@ErikE感谢您的反馈。我看到您已经添加了一个全面的解决方案。我也同意你的观点,电子邮件的实际发送最好不要通过触发器完成。谢谢!分享这份爱怎么样?@ErikE顺便说一句,下一次我将不再“批评”和否决投票,而是希望有建设性的建议和改进的机会。我们中的大多数人都在以某种方式学习=)ThanksI downvote(在有保证的情况下),然后在出现修复缺陷的编辑时删除它。这样,如果海报从未纠正,情况就是正确的(有缺陷的答案会被适当地否决)。海报有机会做出改进,并在评论中为我贴上标签(这就是为什么我要发表评论,以提供标签名称)。如果问题得到解决,我将取消我的否决票。我不知道怎样才能使这更具建设性!想想在更大的环境中,成千上万的人可以复制和粘贴你的代码,却永远无法避免其缺陷。这与你无关。我不得不批评一个触发器不能同时处理多行插入的答案。很抱歉。这不是最佳做法。@ErikE感谢您的反馈。我看到您已经添加了一个全面的解决方案。我也同意你的观点,电子邮件的实际发送最好不要通过触发器完成。谢谢!分享这份爱怎么样?@ErikE顺便说一句,下一次我将不再“批评”和否决投票,而是希望有建设性的建议和改进的机会。我们中的大多数人都在以某种方式学习=)ThanksI downvote(在有保证的情况下),然后在出现修复缺陷的编辑时删除它。这样,如果海报从未纠正,情况就是正确的(有缺陷的答案会被适当地否决)。海报有机会做出改进,并在评论中为我贴上标签(这就是为什么我要发表评论,以提供标签名称)。如果问题得到解决,我将取消我的否决票。我不知道怎样才能使这更具建设性!想想在更大的环境中,成千上万的人可以复制和粘贴你的代码,却永远无法避免其缺陷。这与你无关。