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

sqlserver 触发器 日志

 这个功能我是琢磨了好久,本来我的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,具体的用法网上有的可以查下,这只是我的一家之言,或许大家还有很好的实现,欢迎大家提意见啊!


相关推荐

  • [恶搞]List Control控件item的可编辑操作实现 简介几乎每一个使用vc++编程的人,都将会遇到的列表控件。我们会遇到很多需要代表数据在多个栏目的列表控件场合。默认情况下是不可能的修改列表数据。在这个很小的文章我把一个简单的方法来实现在报告风格的列表控件编辑任意项目的值。这
  • 小表操作 小表操作步骤实验二(开始即开始)电子二班高雅佳15050242004准备阶段:将桌面上的VB软件打开,如没有去程序中的附件中找到VB软件,双击VB软件,将VB软件调整到适合自己的大小。操作阶段:步骤一:点击屏幕左侧工具栏timer图标,在右
  • 【MySQL】三、数据库表操作 数据库表操作:1.数据库表结构的复制CREATETABLEnew_tableLIKEoriginal_table;如果要将原来的数据也复制到新的表格中,使用INSERTINTOnew_tableSELECT*FROM 2.将搜索结
  • 一元多项式的加法以顺序表操作 实验日期:2015/11/09一、实验题目线性表的顺序存储实现及其应用,给出一组数据要求实现一元多项式的加法运算,(9,12)(15,8)(3,2)(26,19)(-4,8)(-13,6)(82,0)​数据已排序;二、实验要求典
  • delphi 注册表操作(4)-另一种注册表操作类 先前给了大家一个Tregistory现在用另一种类实现注册表读写usesRegistry;procedureTForm1.Button1Click(Sender:TObject);vard:string;e:treginifile;begi
  • Delphi2007 关于UAC的问题(注册表操作) <?xmlversion="1.0"encoding="UTF-8"standalone="yes"?><assemblyxmlns="urn:schemas-microsoft-com:asm.v1"manifestVe
  • 驱动注册表操作 //------------------DeleteKey--------------------------------------------NTSTATUSstatus=STATUS_SUCCESS;HANDLEhSubKey;OBJ
  • 如何实现上位机同时与两台DSP实现双向通信呢,若是基于CAN总线的话麻烦给个实现的流程图及详细的实现步 如何实现上位机同时与两台DSP实现双向通信呢,若是基于CAN总线的话麻烦给个实现的流程图及详细的实现步骤。以电脑得装linux系统,请问选哪个linux最好?包括红旗、红帽、ubuntu……不知道我说的对不对?最好详细说一下。申明一点,没有
  • 【赢在走势操盘日志】之2016年12月22日操作策略 根据大盘走势定仓位,根据个股走势定买卖。市场永远是对的,只做市场追随者,不做市场预测者。免责声明:该操盘日志为私人操作日志,通过大盘走势分析,提示自己次日的操作策略。博主为短线操作风格,所以其仓位控制仅适合短线、超短线的仓位控制,不适合中长
  • SEO技术实践操作网站日志分析必杀技      前几天在SEO技术交流群里面看见有人在问为什么要看网站日志,网站日志怎么看,在群里问了一会都没有人答,最后还是一个群友给出了一些以往对日志分析的内容,所以笔者今天就来告诉一下还没有接触网站日志或者接触了网站日志,但是不知道怎么去分析
  • 搜索引擎优化的核心思想 实践操作之SEO技术网站日志分析 内容简介:轻轻松松学seo,甲这里就以遂宁SEO博客的日志给大家展示一;乙商务搜索Baiduspider-ads;丙可是我们还是不知道网站日志长什么样的;丁分析网站日志的时候我们也只需要注意几个常;戊所以笔者今天就来告诉一下还没有接触网站日
  • 【欧声光操盘日志】中央经济工作会议对股市是长期利好 【欧声光操盘日志】中央经济工作会议对股市是长期利好2016年12月19日(星期一)新浪网址http://blog.sina.com.cn/oushengguang(直接访问)(一)今日最新消息:1.各地正在加快落实中央经济工作会议精神;2.

你的评论

就没有什么想说的吗?

最新博客

关于我们 免责声明 移动版

©2017传客网    琼ICP备15003173号-2    

本站部分文章来源于互联网,版权归属于原作者。
本站所有转载文章言论不代表本站观点,如是侵犯了原作者的权利请发邮件联系站长(weishubao@126.com),我们收到后立即删除。
站内所有资源仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您自己承担!

X