0

私はそのような2つのテーブルを持っています:

JOBSテーブル

Jobcode    UserId    Status
101        130       R
102        139       D

USERSテーブル

UserId    Email
130       test@example.com

ストアドプロシージャに電子メールを送信する挿入および更新のトリガーを作成したい:

EXEC dbo.SendMyEmail @email, @jobcode;

ジョブコードが「D」として挿入されたとき、または「D」に更新されたとき。

4

2 に答える 2

3

私の意見では、トリガーでメールを送信することは最適ではありません。

代わりに、キューテーブルに挿入するだけで、テーブルをチェックして電子メールを送信するプロセスを頻繁に実行する必要があります。

電子メールの手順でエラーが発生した場合はどうなりますか?これにより、ジョブの完了ステータスが強制的にロールバックされます。それが軽微なのか、恐らく壊滅的なのかを知っているのはあなただけです。ただし、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';

必要なテーブル:

CREATE TABLE dbo.EmailQueue (
   QueuedDate datetime NOT NULL
      CONSTRAINT DF_EmailQueue_QeueueDate DEFAULT (GetDate()),
   UserID int NOT NULL,
   JobCode int NOT NULL,
   CONSTRAINT PK_EmailQueue PRIMARY KEY CLUSTERED (QueuedDate, UserID, JobCode)
);

CREATE TABLE dbo.EmailSent (
   SentDate datetime NOT NULL
      CONSTRAINT DF_EmailSent_SentDate DEFAULT (GetDate()),
   QueuedDate datetime NOT NULL,
   UserID int NOT NULL,
   JobCode int NOT NULL,
   CONSTRAINT PK_EmailSent PRIMARY KEY CLUSTERED (SentDate, QueuedDate, UserID, JobCode)
);

次に、SQLジョブから1分に1回、次のストアドプロシージャを実行します。

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で何もチェックせずに、上記のすべてを入力しました。タイプミスがある可能性があります。許してください。

于 2012-08-03T05:26:22.597 に答える
2

データ型などについてはよくわかりませんが、少なくとも正しい方向に進むはずです。それが役に立てば幸い...

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

さらに、コメントで説明されているように、トリガーからの電子メールの送信も最善ではありませんが、これが質問で求められているものであるため、含まれています。他の回答で言及されているキューなど、電子メールを送信するための代替オプションをお勧めします。

于 2012-08-02T22:33:32.023 に答える