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 + ”;

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 + ”;

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 = ”;

set @xmlstr = @xmlstr + ”;

set @xmlstr = @xmlstr + ” + convert(varchar(3),@opttype) + ”;

set @xmlstr = @xmlstr + ” + @tabname + ”;

set @xmlstr = @xmlstr + ” + @pk_pre_name + ”;

set @xmlstr = @xmlstr + ”;

set @xmlstr = @xmlstr + ”;

set @xmlstr = @xmlstr + @optinfo;

set @xmlstr = @xmlstr + ”;

set @xmlstr = @xmlstr + ”;

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)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐