触发器实现记录操作表的日志

 这个功能我是琢磨了好久,本来我的sqlserver方面的知识深入了解的就不多,关键的难点是用变量代替字段名,然后获取字段在表中存的值,再赋给另外一个变量,我之所以这么做,因为后面好几处要用到这个字段的名称,我才用变量代替,便于修改,可就是实现花费了很长时间,网上这么方面的资料又少,可终究还是找到了解决方案,希望大家以后遇到同样的问题不至于头大,把具体的实现分享给大家


CREATE trigger [dbo].[trg_new_course]
on [dbo].[course]
for insert,delete,update
as
begin
declare @tabname varchar(50),
  @pkname varchar(20),
  @pkvalue varchar(20),
  @opttype int,
  @optip varchar(20),
  @optsql varchar(200),
  @xmlstr nvarchar(500);

declare @optinfo nvarchar(500),
  @id_i int,
  @id_d int;

declare @min_id int, --最小的字段号
  @total int,  --记录总数
  @row_count int, --循环变量
  @temp_name varchar(100), --临时字段名
  @temp_pre_name varchar(100), --带字段类型前缀的变量
  @temp_type varchar(100), --临时字段类型
  @temp_value varchar(100), --临时字段值
  @xmlnode_value varchar(100), --xml的节点值
  @sql_name varchar(100),  --sql操作相关的字段
  @sql_value varchar(100), --sql操作相关的字段值
  @sql nvarchar(200),   --存储动态sql
  @pk_pre_name varchar(20) --带类型前缀的关键字段名
set @sql_name = '';
set @sql_value = '';
set @row_count = 1;

set @pkname = 'id'; --关键字名称
set @tabname = 'course'; --操作的表名
set @optinfo = '';

select @id_i=id from inserted;
select @id_d=id from deleted;

select @temp_type = data_type from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @tabname and column_name = @pkname;
if (@temp_type = 'int')
 begin
  set @pk_pre_name = 'i' + @pkname
 end
else if(@temp_type = 'float')
 begin
  set @pk_pre_name = 'f' + @pkname
 end
else if(@temp_type = 'decimal')
 begin
  set @pk_pre_name = 'd' + @pkname
 end
else if(@temp_type = 'datetime')
 begin
  set @pk_pre_name = 'da' + @pkname
 end
else
 begin
  set @pk_pre_name = 'c' + @pkname
 end
if @id_i is null and @id_d is not null --删除操作
 begin
  set @pkvalue = @id_d;
  set @opttype = 1;
  --若变量的类型不是字符串型
  set @pkvalue = convert(varchar(200),@pkvalue);
  --生成执行删除操作的sql语句
  set @optsql = 'delete from ' + @tabname + ' where ' + @pkname + '=' + @pkvalue;
  --生成删除操作字段信息的xml表示
  set @optinfo = @optinfo + '<' + @pkname +'>';
  set @optinfo = @optinfo + @pkvalue;
  set @optinfo = @optinfo + '</' + @pkname +'>';
 end
else
 begin
  set @pkvalue = @id_i;
  select * into temps from inserted;--这句必须写动态sql中时找不到inerted这个逻辑表的
  select @min_id = max(ordinal_position) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @tabname;
  select @total = count(1) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @tabname;
  while(@row_count <= @total)
  begin
   select @temp_name = column_name,@temp_type = data_type from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @tabname and ordinal_position = @min_id;
   if(@temp_type = 'int')
   begin
    declare @temp_in int;
    SET  @sql  = 'select @temp_in = '  +  @temp_name   +  '  from temps;';
    EXEC SP_EXECUTESQL  @Sql, 
 N'@temp_in  int OUTPUT', @temp_in  OUTPUT;
    set @xmlnode_value = convert(varchar(100),@temp_in);
    set @temp_value = @xmlnode_value;
    set @temp_pre_name = 'i' + @temp_name;
   end
   else if(@temp_type = 'float')
   begin
    declare @temp_inf float;
    SET  @sql  = 'select @temp_inf = '  +  @temp_name   +  '  from temps;';
    EXEC SP_EXECUTESQL  @Sql,  N'@temp_inf  float OUTPUT', @temp_inf  OUTPUT;
    set @xmlnode_value = convert(varchar(100),@temp_inf);
    set @temp_value = @xmlnode_value;
    set @temp_pre_name = 'f' + @temp_name;
   end
   else if(@temp_type = 'decimal')
   begin
    declare @temp_ind float;
    SET  @sql  = 'select @temp_ind = '  +  @temp_name   +  '  from temps;';
    EXEC SP_EXECUTESQL  @Sql,  N'@temp_ind  decimal(18,0) OUTPUT', @temp_ind  OUTPUT;
    set @xmlnode_value = convert(varchar(100),@temp_ind);
    set @temp_value = @xmlnode_value;
    set @temp_pre_name = 'd' + @temp_name;
   end
   else
   begin
    declare @temp_inc varchar(200);
    SET  @sql  = 'select @temp_inc = '  +  @temp_name   +  '  from temps;';
    EXEC SP_EXECUTESQL  @Sql,  N'@temp_inc  varchar(200) OUTPUT', @temp_inc  OUTPUT;
    set @xmlnode_value = convert(varchar(100),@temp_inc);
    set @temp_value = '''' + @xmlnode_value + '''';
    set @temp_pre_name = 'c' + @temp_name;
   end
   --生成插入/修改操作相关数据信息的xml表示
   set @optinfo = @optinfo + '<' + @temp_pre_name + '>';
   set @optinfo = @optinfo + @xmlnode_value;
   set @optinfo = @optinfo + '</' + @temp_pre_name + '>';
   if @id_i is not null and @id_d is null  -- 插入操作
   begin
    --生成插入操作执行的sql语句
    if(@temp_name <> @pkname)
    begin
     set @sql_name = @sql_name + ',' + @temp_name;
     set @sql_value = @sql_value + ',' + @temp_value;
    end
   end
   else if @id_i is not null and @id_d is not null --更新操作
   begin
    --生成修改操作执行的sql语句
    if(@temp_name <> @pkname)
    begin
     set @sql_name = @sql_name + ',' + @temp_name + '=' + @temp_value;
    end
   end
   select @min_id = ordinal_position from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'course' and ordinal_position < @min_id;
   set @row_count = @row_count + 1;
  end
  if @id_i is not null and @id_d is null  -- 插入操作
  begin
   --生成执行插入操作的sql语句
   set @opttype = 0;
   set @optsql = 'insert into ' + @tabname + '(' + substring(@sql_name,2,len(@sql_name)) + ')' + ' values(' + substring(@sql_value,2,len(@sql_value)) +')';
  end
  else if @id_i is not null and @id_d is not null --更新操作
  begin
   --生成执行修改操作的sql语句
   set @opttype = 3;
   set @optsql = 'update ' + @tabname + ' set ' + substring(@sql_name,2,len(@sql_name)) + ' where ' + @pkname + '=' + @pkvalue;
  end 
  drop table temps;
 end

set @xmlstr = '<?xml version="1.0" encoding="gb2312" ?><root>';
set @xmlstr = @xmlstr + '<baseinfo>';
set @xmlstr = @xmlstr + '<opttag>' + convert(varchar(3),@opttype) + '</opttag>';
set @xmlstr = @xmlstr + '<opttab>' + @tabname + '</opttab>';
set @xmlstr = @xmlstr + '<pkname>' + @pk_pre_name + '</pkname>';
set @xmlstr = @xmlstr + '</baseinfo>';
set @xmlstr = @xmlstr + '<optinfo>';
set @xmlstr = @xmlstr + @optinfo;
set @xmlstr = @xmlstr + '</optinfo>';
set @xmlstr = @xmlstr + '</root>';

select @optip=client_net_address from sys.dm_exec_connections where Session_id=@@spid;
if(@pkvalue is null)
begin
 set @pkvalue = -1;
end
insert into optlog values(@tabname,@pkname,@pkvalue,@opttype,@optip,getdate(),@optsql,@xmlstr);

print '操作执行成功';
end

 

红色标注的部分我认识是实现的难点,就是用到了sqlserver的系统存储过程sp_executesql,具体的用法网上有的可以查下,这只是我的一家之言,或许大家还有很好的实现,欢迎大家提意见啊!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值