用于保存对审计跟踪表的更改的 Sql 触发器

Posted

技术标签:

【中文标题】用于保存对审计跟踪表的更改的 Sql 触发器【英文标题】:Sql trigger to save changes to an audit trail table 【发布时间】:2011-04-01 22:12:42 【问题描述】:

我开始使用 ADS sql 表触发器来存储对一个特定表所做的更改。这是一个想法:

//-------- sql trigger to store changes on patients table to auditLog Table
//----------------------------------------------------------------------
declare cChanges Char( 5000 );
declare allColumns Cursor ;
declare FieldName Char( 25 );
declare StrSql  Char( 255 );
declare @new cursor as select * from __new;
declare @old cursor as select * from __old; 
open @old; 
fetch @old;
open @new; 
fetch @new;
Set cChanges = '';
Open AllColumns as Select * from system.columns where parent = 'patients';
while fetch allColumns DO
// Try
   FieldName = allColumns.Name;
   StrSql = 'IF @new.'+FieldName
          + '<> @old.'+FieldName
          +' and @old.'+FieldName + '<> [ ] THEN ' 
                       + 'cChanges = Trim( '+cChanges+' ) + @old.'+FieldName
                                   + ' Changed to ' + '@new.'+fieldname
                                   + ' | '+ 'ENDIF ; ' ;
   Execute Immediate StrSql ;
//    Catch ALL
//    End Try;
End While;
if cChanges <> '' THEN
    Insert Into AuditLog ( TableKey, Patient, [table], [user], creation, Changes ) 
         values( @new.patient, @new.patient, [Patietns], User(), Now(), cChanges ) ;
ENDIF;
CLOSE AllColumns;
//--------------------------

上面报告变量cChanges的触发代码错误不存在。

有人可以帮忙吗?

雷纳尔多。

【问题讨论】:

可能不相关,但“values(@new.patient, @new.patient, [Patietns], User()...”是一个错字(即 [Patietns]? 【参考方案1】:

问题确实是你不能在立即执行的脚本中访问局部变量。你可以做些什么来解决这个问题是使用临时表:

//-------- sql trigger to store changes on patients table to auditLog Table
//----------------------------------------------------------------------
declare cChanges Char( 5000 );
declare allColumns Cursor ;
declare FieldName Char( 25 );
declare StrSql  Char( 255 );
Set cChanges = '';
Open AllColumns as Select * from system.columns where parent = 'patients';
while fetch allColumns DO
// Try
   FieldName = allColumns.Name;

   StrSql = 'SELECT n.FieldName newVal,'
            + 'o.FieldName oldVal '
            + 'INTO #MyTrigTable '
            + 'FROM __new n, __old o';

   EXECUTE IMMEDIATE strSQL;

   IF ( SELECT oldVal FROM #myTrigTable ) <> '' THEN
      IF ( SELECT newVal FROM #myTrigTable ) <> ( SELECT oldVal FROM #myTrigTable ) THEN
         cChanges = 'Construct_SomeThing_Using_#myTrigTable_or_a_cursorBasedOn#MyTrigTable';
         INSERT INTO AuditLog ( TableKey, Patient, [table], [user], creation, Changes ) 
         SELECT patient, patient, 'Patietns', User(), Now(), cChages FROM __new ;
      END;
   END;
   DROP TABLE #myTrigTable;
//    Catch ALL
//    End Try;
End While;
CLOSE AllColumns;
//--------------------------

【讨论】:

【参考方案2】:

我认为问题与您的动态 SQl 尝试设置触发器主体中声明的值有关。

例如您的 cChanges = TRIM( 语句可能会导致问题,因为 cChanges 不存在该上下文。

您应该使用绑定变量来完成此操作,而不是尝试使用 = 符号进行设置。

你可以在他们的文档中看到他们说你不能直接访问这些变量

http://devzone.advantagedatabase.com/dz/webhelp/advantage9.1/advantage_sql/sql_psm_script/execute_immediate.htm

【讨论】:

以上是关于用于保存对审计跟踪表的更改的 Sql 触发器的主要内容,如果未能解决你的问题,请参考以下文章

特定表的 Oracle 11g 审计跟踪

如果 Column_X 更新,PLSQL 触发器记录对审计表的更新

T-SQL 之 触发器

T-SQL 触发器 - 审计列更改

外键的审计触发器

Oracle 中的审计