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 

これを正しく理解している場合、1 つのレコードで姓が更新され、別のレコードで同時に名が更新された場合、両方のレコードが名と姓の両方が変更されたものとしてログに記録されます。あれは正しいですか?もしそうなら、どうすればカーソルを使わずに正しく動作させることができますか?

問題を解決するために考えることができる唯一の方法は、カーソルを使用することですが、それは良い考えではありません。どんな助けでも大歓迎です。

ありがとう!

4

2 に答える 2

2

複数のレコードが更新されると、そのままのコードは機能しません。

その監査テーブル構造に本当に縛られていますか? 古いデータと新しいデータの両方を保存するだけでなく、データを変更したアプリケーションまたはユーザーの ID とデータの日付を保存する方が便利です。この構造では、誰かが元に戻したい変更を行った場合、データを元に戻すのが非常に難しくなり、いつ、誰が変更を行ったかを特定できなくなります。監査テーブルをまだ実装していない場合は、最初にそれらを再設計することを真剣に検討します。

あなたが示したデザインに行き詰まった場合は、各フィールドを通過するときにデータを格納する一時テーブルまたはテーブル変数を作成します。最初のレコードには isert を使用し、次に他のレコードのそれぞれにマージ ステートメントを使用して、レコードが既に存在する場合は更新するか、存在しない場合は新しいレコードを挿入します。一時テーブルが作成されたら、そのテーブルから選択して監査テーブルに挿入します。これはカーソルよりも高速ですが、監査テーブルの設計が非常に悪いため、高速ではありません。一般に、コンマ区切りのリストを含むようにテーブルを設計するべきではありません。特に、トリガーのようにクエリでパフォーマンスが必要な場合はそうではありません。

于 2012-08-30T14:23:16.463 に答える
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

いくつかの追加のいじりは、余分な区切り文字を排除することができます。

于 2012-08-30T15:37:48.187 に答える