我需要创建一个触发器,只要在主表中修改记录,就会将记录添加到队列表中。添加到队列表的记录必须包含为该记录修改的每个字段。
到目前为止,我有这个代码,但我认为它不适用于更新的多行:
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
如果我正确理解这一点,如果一条记录的姓氏已更新,而另一条记录同时更新了第一个名称,那么两条记录都会记录为同时更改了第一个和最后一个名称。那是对的吗?如果是这样,如何在不使用游标的情况下使其正常工作?
我能想到解决问题的唯一方法是使用光标,但我知道这不是一个好主意。任何帮助将不胜感激。
谢谢!
答案 0 :(得分:2)
如果更新了多个记录,您的代码将无法正常工作。
您是否真的与审计表结构相关联?我们发现存储旧数据和新数据以及应用程序的ID或更改数据的人员以及数据的日期更有用。如果有人进行了您想要撤消的更改,并且不允许您确定何时或谁进行更改,则此结构将很难检索数据。如果你还没有实现审计表,我首先会仔细考虑重新设计它们。
如果我坚持你所展示的设计,我会创建临时表或表变量来存储每个字段的数据。我首先使用一个isnert用于第一个,然后为每个其他用户使用合并语句,如果已经是tehre则更新记录,如果不是,则更新新的记录。填充临时表后,我将从该表中选择插入到审计表中的selct。这将比游标更快,但由于审计表的设计非常糟糕,因此速度不快。通常不应该设计一个表来包含逗号分隔列表,特别是当您需要在查询中执行性能时,就像在触发器中一样。
答案 1 :(得分: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
一些额外的摆弄可以消除额外的分隔符。