2012-08-30 80 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