Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 不使用光标更新触发器_Sql_Sql Server_Triggers_Cursor - Fatal编程技术网

Sql 不使用光标更新触发器

Sql 不使用光标更新触发器,sql,sql-server,triggers,cursor,Sql,Sql Server,Triggers,Cursor,我需要创建一个触发器,每当主表中的记录被修改时,该触发器就会将记录添加到队列表中。添加到队列表的记录必须包含为该记录修改的每个字段 到目前为止,我已经有了这段代码,但我认为它不适用于多行更新: ALTER TRIGGER [dbo].[tr_EmpHistory] ON [dbo].[employeeData] FOR UPDATE AS BEGIN DECLARE @FieldsUpdated xml, @FieldsUpdated1 varchar(100)

我需要创建一个触发器,每当主表中的记录被修改时,该触发器就会将记录添加到队列表中。添加到队列表的记录必须包含为该记录修改的每个字段

到目前为止,我已经有了这段代码,但我认为它不适用于多行更新:

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 
如果我理解正确,如果一条记录的姓氏被更新,而另一条记录的姓氏被同时更新,那么这两条记录都将被记录为更改了姓氏和姓氏。对吗?如果是这样的话,我如何在不使用光标的情况下使其正常工作

我认为解决这个问题的唯一方法是使用光标,但我知道这不是一个好主意。任何帮助都将不胜感激


谢谢

如果更新了多个记录,您的现有代码将无法工作

您真的与审计表结构有关联吗?我们发现存储新旧数据以及应用程序或更改数据的人的id和数据日期更有用。如果有人做出了您想要撤销的更改,并且不允许您确定何时或谁做出了更改,那么这种结构将使您很难检索回数据。如果你还没有实现审计表,我将首先认真考虑重新设计它们。 如果我坚持使用您展示的设计,我会创建临时表或表变量,以便在遍历每个字段时存储数据。我会对第一条使用isnert,然后对其他每条使用merge语句来更新记录(如果已经是tehre),或者插入一条新记录(如果不是)。填充temp表后,我将使用该表中的selct插入到审计表中。这将比游标快,但由于审核表的设计非常糟糕,因此速度不快。人们通常不应该设计一个包含逗号分隔列表的表,特别是当您需要查询性能时,就像在触发器中一样

您可以使用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

一些额外的修改可以消除额外的分隔符。

请不要使用隐含连接语法,它是SQL反模式!它不适用于审核表,并且没有任何内容存储在逗号分隔的列表中。每当我们的数据更改以更新第三方时,我们必须呼叫第三方web服务。此队列表将存储更新的记录以及在XML中更改的特定字段。服务将运行此队列表并获取任何更改字段的当前值,并调用第三方Web服务通知他们新更改的数据。auditEmployeeData不是审核表吗?请原谅我这么想。我不需要知道旧值是什么,也不需要知道是谁/什么改变了数据。我只关心数据是否真的被更改了。我想这可能有用。让我做一些测试来确定。谢谢这正是我所需要的。谢谢