2012-08-30 122 views
0

我需要創建一個觸發器,只要在主表中修改記錄,就會將記錄添加到隊列表中。添加到隊列表中的記錄必須包含爲該記錄修改的每個字段。不使用光標更新觸發器

我有這樣的代碼,到目前爲止,但我不認爲它會爲更新多個行:

ALTER TRIGGER [dbo].[tr_EmpHistory]  
ON [dbo].[employeeData] 
FOR UPDATE 
AS 
BEGIN  
DECLARE @FieldsUpdated xml, 
@FieldsUpdated1 varchar(100)  
SELECT @Fieldsupdated1 = ' ' 
SELECT 
@FieldsUpdated1 = @FieldsUpdated1 + ' emp_bankaccountnumber' 
FROM inserted as a, 
deleted as b 
WHERE a.emp_id = b.emp_id    
AND a.emp_bankAccountNumber <> b.emp_bankAccountNumber 
SELECT  
@FieldsUpdated1 = @FieldsUpdated1 + 'emp_salary ' 
FROM inserted as a,   
deleted as b 
WHERE a.emp_id = b.emp_id  
AND a.emp_salary <> b.emp_salary 

SELECT  
@FieldsUpdated1 = @FieldsUpdated1 + 'emp_SSN ' 
FROM inserted as a, 
deleted as b 
WHERE a.emp_id = b.emp_id    
AND a.emp_SSN <> b.emp_SSN 
SELECT 
@FieldsUpdated1 = @FieldsUpdated1 + 'emp_lname ' 
FROM inserted as a, 
deleted as b 
WHERE a.emp_id = b.emp_id   
AND a.emp_lname <> b.emp_lname 
SELECT  
@FieldsUpdated1 = @FieldsUpdated1 + 'emp_fname ' 
FROM inserted as a, 
deleted as b 
WHERE a.emp_id = b.emp_id  
AND a.emp_fname <> b.emp_fname 
SELECT 
@FieldsUpdated1 = @FieldsUpdated1 + 'emp_manager ' 
FROM inserted as a, 
deleted as b 
WHERE a.emp_id = b.emp_id   
AND a.emp_manager <> b.emp_manager 
SELECT @Fieldsupdated = ( 
SELECT COLUMN_NAME AS Name 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'employeeData' 
AND CHARINDEX(COLUMN_NAME,(ltrim(rtrim(@fieldsupdated1)))) > 0 
FOR XML AUTO, ROOT('Fields')) 

INSERT INTO auditEmployeeData( 
audit_emp_id, 
audit_emp_bankAccountNumber, 
audit_emp_salary, 
audit_emp_SSN, 
audit_emp_lname, 
audit_emp_fname, 
audit_emp_manager, 
ColumnsUpdated) 

SELECT emp_id, 
emp_bankAccountNumber, 
emp_salary,  
emp_SSN, 
emp_lname, 
emp_fname,  
emp_manager,  
@FieldsUpdated 
FROM INSERTED 
END 
GO 

如果我理解正確這一點,如果一個記錄都姓更新和再創新得到了第一個名字同時更新,那麼這兩個記錄都會記錄爲第一個和最後一個名字都改變了。那是對的嗎?如果是這樣,我怎麼能不使用光標正確工作?

我認爲解決問題的唯一方法是使用遊標,但我知道這不是一個好主意。任何幫助,將不勝感激。

謝謝!

+2

請不要使用隱含的連接語法,它是一個SQL反模式! – HLGEM

回答

0

您可以使用CASE建立一個價值一行一行地表示變更列:

select i.emp_id, 
    case when i.foo <> d.foo then ',foo' else '' end + 
    case when i.bar <> d.bar then ',bar' else '' end as changedcolumns 
    from inserted as i inner join 
    deleted as d on d.emp_id = i.emp_id 

一些額外擺弄可以消除多餘的分隔符。

+0

我認爲這可能有效。讓我做一些測試來確保。謝謝! – jkruer01

+0

這正是我所需要的。謝謝! – jkruer01

2

如果多個記錄更新,您的代碼將不起作用。

你真的被綁定到審計表結構嗎?我們發現存儲新舊數據以及更改數據的應用程序或個人的ID以及數據的日期更有用。如果有人進行了想要更改的更改,並且不允許您確定何時或誰進行了更改,則此結構將使恢復數據變得非常困難。如果您還沒有實施審計表,我會首先仔細考慮重新設計它們。

如果我堅持使用您所展示的設計,我會創建臨時表或表變量來存儲數據,因爲您會遍歷每個字段。我將首先使用isnert,然後爲其他每個人使用合併語句,以更新記錄,如果已經是tehre或者如果不是則插入新記錄。一旦臨時表被填充,然後我將從該表中選擇插入到審計表中。這將比光標快,但由於審覈表的設計非常糟糕,所以速度不快。一般不應該設計一個表格來包含逗號分隔列表,特別是當你需要查詢性能時,不會像觸發器那樣包含逗號分隔列表。

+0

它不適用於審計表,也不會在逗號分隔列表中存儲任何內容。每當我們的數據發生變化以更新第三方時,我們都必須致電第三方Web服務。此隊列表將存儲更新的記錄以及在XML中更改的特定字段。服務將通過此隊列表運行並獲取任何已更改字段的當前值,並調用第三方Web服務來通知它們新的已更改數據。 – jkruer01

+3

auditEmployeeData不是審計表嗎?原諒我以爲是的。 – HLGEM

+0

我不需要知道舊值是什麼或者誰改變了數據。我只關心數據實際發生了變化。 – jkruer01