我们在操作表的时候难免会遇到误删除,或者删掉的数据还想恢复的情况。
也许细心的朋友会用begin tran rollback/commit 这种事务来避免出现失误,但这并不是最保险的。
如果提交了事物发现删错了或者忘记提交从而导致表被锁,这些问题总是不可避免的。
废话不多说了,下面直接进入正题,通过触发器记录删除日志,避免误删除带来的尴尬。
下面这段sql粘过去直接运行,建立一个存储过程:
create procedure [dbo].[sp_delete_log]
@tablename varchar(50)
as
begin
set nocount on;
if not exists(select * from sys.tables where name = @tablename and type = 'u' )
begin
print'error:not exist table '+@tablename
return
end
if (@tablename like'backup_%' or @tablename='update_log' )
begin
--print'error:not exist table '+@tablename
return
end
--================================判断是否存在 update_log 表============================
if not exists(select * from sys.tables where name = 'update_log' and type = 'u')
create table update_log
(
updateguid varchar(36),
updatetime datetime,
tablename varchar(20),
updatetype varchar(6),
rollbacksql varchar(1000)
)
--=================================判断是否存在 backup_ 表================================
if not exists(select * from sys.tables where name = 'backup_'+@tablename and type = 'u')
begin
--declare @sql varchar(500)
--set @sql='select top 1 newid() as [updateguid],* into backup_'+@tablename+' from '+ @tablename+'
-- delete from backup_'+@tablename
--select @sql
--exec(@sql)
declare test_cursor cursor for
select column_name,data_type,character_maximum_length from information_schema.columns
where table_name=@tablename
open test_cursor
declare @sqltb nvarchar(max)=''
declare @column_name nvarchar(50),@data_type varchar(20),@character_maximum_length int
fetch next from test_cursor into @column_name,@data_type,@character_maximum_length
while @@fetch_status=0
begin
set @sqltb=@sqltb+'['+@column_name+'] '+@data_type+case isnull(@character_maximum_length,0) when 0 then '' when -1 then '(max)' else'('+cast(@character_maximum_length as varchar(10))+')' end+','
fetch next from test_cursor into @column_name,@data_type,@character_maximum_length
end
set @sqltb='create table backup_'+@tablename+' (updateguid varchar(36),'+substring(@sqltb,1,len(@sqltb)-1)+')'
exec (@sqltb)
close test_cursor
deallocate test_cursor
end
--======================================判断是否存在 delete 触发器=========================
if not exists(select * from sys.objects where name = 'tg_'+@tablename+'_delete' and type = 'tr')
begin
declare @sqltr nvarchar(max)
set @sqltr='
create trigger tg_'+@tablename+'_delete
on '+@tablename+'
after delete
as
begin
set nocount on;
--==============================获取guid==========================================
declare @newid varchar(36)=newid()
--==============================将删掉的数据插入备份表============================
insert into [dbo].[backup_'+@tablename+']
select @newid,* from deleted
--==============================记录日志和回滚操作的sql===========================
--*********************生成列名**********************
declare @column nvarchar(max)=''''
select @column+='',[''+column_name+'']'' from information_schema.columns
where table_name='''+@tablename+'''
and columnproperty(object_id('''+@tablename+'''),column_name,''isidentity'')<>1 --非自增字段
set @column=substring(@column,2,len(@column))
insert into [dbo].[update_log]
select @newid,getdate(),'''+@tablename+''',''delete'',''insert into '+@tablename+' select ''+@column+'' from backup_'+@tablename+' where updateguid=''''''+@newid+''''''''
end
'
exec(@sqltr)
end
end
接着我们新建一张测试表,并且随便往表中插入两组数据:
create table test ( id int, name varchar(10), msg varchar(10) ) insert into test select 1,'aa','hahah' union all select 2,'bb','heihei'
下面执行这个sp,在给test表添加回滚日志:
exec sp_delete_log 'test'
细心的你不难发现,这时候数据库里面应该会多出两张表:
然后我们删掉一条数据:
delete from test where id=1
再查看那两张表:
没错,这时候日志表里有数据了,然后我们把 update_log 表中的 rollbacksq l这一列对应的值copy出来执行一下:
insert into test select [id],[name],[msg] from backup_test where updateguid='b0cbbc4f-3432-4d4f-9e17-f17209bf6745'
别copy我上面这段sql,因为guid肯定是不一样的!
然而,数据恢复了:
最后,delete日志的介绍就结束了,唯一的不满足的是只能作用在delete 操作,其实update 操作也同样需要这样的回滚日志。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。如有错误或未考虑完全的地方,望不吝赐教。