2011-04-27 16 views
4

我一直在試圖避免在這種特殊情況下使用遊標,只是因爲我不喜歡權衡,而且它恰好發生了,我正在使用的一個過程使觸發器看起來像正確的行動方式。在INSERT INTO Table(etc)SELECT * FROM Table2期間,如何獲取觸發器以觸發每個插入的行?

存儲過程插入基於複雜子句組合的記錄,使用插入觸發器向目標用戶發送電子郵件,告訴他們訪問站點。這很簡單,而且工作正常。

但是,另一個過程是夜間運行並重新分配所有未查看的記錄。我這樣做的方式是根據從指定日期字段的選擇開始執行另一次插入。即:

INSERT INTO Table (ID, User, AssignDate, LastActionDate) 
    SELECT 
     ID 
     ,User 
     ,GETDATE() [AssignDate] 
     ,GETDATE() [LastModifiedDate] 
    FROM Table2 
     /*snip*/ 

該觸發器對單個插入有效,但上面的select語句僅對最後一個插入行起作用。有沒有辦法解決這個問題?它毀了整個事情!

編輯(觸發代碼):

ALTER TRIGGER dbo.Notify 
    ON dbo.Table 
    AFTER INSERT 
AS 
BEGIN 

    DECLARE @EmailSender varchar(50)='Sender Profile' 
    DECLARE @Identity int 
    DECLARE @User varchar(20) 
    DECLARE @Subject varchar(50) 

    SET @[email protected]@Identity 

    SELECT @User=User, @Subject='(' + CONVERT(varchar,@Identity) + ')!' 
    FROM Table 
    WHERE 
     [email protected] 

    exec msdb.dbo.sp_send_dbmail 
     @[email protected], 
     @[email protected] 
     @[email protected], 
     @body='//etc' 

END 
+4

SQL Server中的觸發器每個語句觸發一次,而不是每行觸發一次。因此,您需要編寫觸發器代碼來處理存在於「插入」和/或「刪除」中的多行。通常,這仍然可以在不使用遊標的情況下完成。但是我們需要看到更多的代碼才能提供建議 - 目前所展示的只是一個標準的插入語句。 – 2011-04-27 14:52:38

+0

已添加到觸發器代碼中。 – 2011-04-27 15:04:41

+0

我想你會需要一個遊標。我認爲沒有任何東西允許您一次插入多個電子郵件。 – 2011-04-27 15:09:51

回答

7

插入觸發器是爲批量插入調用一次,但在扳機上,你可以使用特殊inserted表以獲取所有插入的行。

因此,假設您有一個INSERT觸發器像這樣的,它記錄插入table

create trigger trgInsertTable 
on dbo.table 
for insert 
as 
    insert tableLog(name) 
    select name from inserted 

有了這個觸發器的所有行,當你犯了一個批量插入上table,該tableLog充滿相同的行數插入,要table

對於你特定的觸發,因爲你需要調用存儲過程的每一行,你需要使用遊標:

ALTER TRIGGER dbo.Notify 
    ON dbo.Table 
    AFTER INSERT 
AS 
BEGIN 

    DECLARE @EmailSender varchar(50)='Sender Profile' 
    DECLARE @User varchar(20) 
    DECLARE @Subject varchar(50) 

    DECLARE cursor CURSOR FOR 
     SELECT User, '(' + CONVERT(varchar, Id) + ')!' 
     FROM inserted 

    OPEN cursor 
    FETCH NEXT FROM cursor INTO @User, @Subject 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     exec msdb.dbo.sp_send_dbmail 
      @[email protected], 
      @[email protected] 
      @[email protected], 
      @body='//etc' 
     FETCH NEXT FROM cursor INTO @User, @Subject 
    END 
    CLOSE cursor 
    DEALLOCATE cursor 

END 

我沒有測試,但應該工作

+0

我想我應該完全跳過觸發器,然後將電子郵件代碼移回存儲過程,該存儲過程正在處理所有內容。 – 2011-04-27 15:14:44

+0

@downvoter,謹慎解釋? – 2013-10-13 15:51:57

+1

只是一個非常次要的評論 - 在不區分大小寫的情況下,您需要爲光標選擇不同於'cursor'的名稱 – Jan 2013-12-12 17:08:15

4

如果您發送電子郵件,我不會做,從一個觸發器。你真的希望人們不能插入記錄,因爲電子郵件服務器已關閉?

通常情況下,從觸發器插入記錄到表中,然後有一個作業發送每分鐘左右運行的電子郵件,並將電子郵件狀態更新爲發送,並在發送每個時間時將發送的日期時間添加到表中記錄被髮送。這不僅可以讓您在電子郵件停止時插入記錄,還可以移動循環以將每個單獨的電子郵件發送到用戶無法訪問的表格(因此,處理許多記錄的任何延遲只會影響新用戶,而不會影響其他任何人)允許您查看您何時發送電子郵件的歷史記錄,這有助於人們詢問他們爲什麼沒有收到郵件。您還可以在表格中記錄電子郵件發送失敗以幫助識別不良電子郵件地址。

+1

每分鐘運行一次光標?看起來很醜! – 2011-04-27 15:20:39

+0

很難在沒有光標或循環的情況下一次只發送一封電子郵件給一個人。至少如果他們在另一張桌子上,他們不會干擾正常的操作。 – HLGEM 2011-04-27 15:26:27

+0

@C Bauer,@ HLGEM - 這比在一個觸發器中運行光標更可取。此外,它允許您通過簡單地寫入通知表來禁用開發機器上的通知,但禁用電子郵件發送處理。如果有需要,這種方法還可以讓您將發送到服務的電子郵件外部化。 – Thomas 2011-04-27 15:35:17

相關問題