Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 创建状态更新触发器_Sql_Sql Server_Sql Server 2005_Triggers - Fatal编程技术网

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(在有保证的情况下),然后在出现修复缺陷的编辑时删除它。这样,如果海报从未纠正,情况就是正确的(有缺陷的答案会被适当地否决)。海报有机会做出改进,并在评论中为我贴上标签(这就是为什么我要发表评论,以提供标签名称)。如果问题得到解决,我将取消我的否决票。我不知道怎样才能使这更具建设性!想想在更大的环境中,成千上万的人可以复制和粘贴你的代码,却永远无法避免其缺陷。这与你无关。