在生产数据库做CURD操作时,可能会有执行某条语句误操作的情况发生,针对这个种情况有两点建议:

1、 在SQL SERVER上开启事务确认功能,当执行完语句后确认无误,再提交事务。(开启方法见附件图片)。

2、 新建存储过程,粘贴附件脚本。此存储过程执行后能够自动产生两个操作日志表,自动记录CRUD的所有操作。适用于提交事务后才发现错误的情况。只需要打开表UPDATE_LOG,粘贴RollbackupSQL里的语句执行即可恢复数据。

注意:1)如果表中有自增长的ID,所恢复数据的ID值是最大ID+1。

2)由于正常操作也会回写操作日志,注意及时清理日志表,或者在执行完后删掉新建的存储过程、触发器及表。

 
回滚脚本,执行后数据要记录的表名

CREATE PROCEDURE [dbo].[SP_UPDATE_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(MAX),

            ExecSQL VARCHAR(500)

        )

    --=================================判断是否存在 BACKUP_ 表================================

    IF NOT EXISTS(SELECT * FROM sys.tables WHERE NAME = 'BACKUP_'+@TABLENAME AND TYPE = 'U')

    BEGIN

        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),UpdateType Varchar(10),'+SUBSTRING(@SQLTB,1,LEN(@SQLTB)-1)+')'

        EXEC (@SQLTB)

        CLOSE test_Cursor

        DEALLOCATE test_Cursor

    END

    --======================================判断是否存在 UPDATE 触发器=========================

    IF NOT EXISTS(SELECT * FROM sys.objects WHERE NAME = 'tg_'+@TABLENAME+'_Update' AND TYPE = 'TR')

    BEGIN

        DECLARE @SQLTR NVARCHAR(MAX)

        SET @SQLTR='

CREATE TRIGGER tg_'+@TABLENAME+'_Update

    ON  '+@TABLENAME+'

    AFTER Update,Delete,Insert

AS

BEGIN 

    SET NOCOUNT ON;

    --==============================获取GUID==========================================

    DECLARE @NEWID VARCHAR(36)=NEWID()

    --===========================将删掉或新增的数据插入备份表=========================

    DECLARE @ROWCOUNT INT

    INSERT INTO [dbo].[BACKUP_'+@TABLENAME+']

    SELECT @NEWID,''DELETE'',* FROM deleted

    SET @ROWCOUNT=@@ROWCOUNT

    IF @ROWCOUNT>0

    BEGIN

        INSERT INTO [dbo].[BACKUP_'+@TABLENAME+']

        SELECT @NEWID,''INSERT'',* FROM inserted

    END

    ELSE

    BEGIN

        INSERT INTO [dbo].[BACKUP_'+@TABLENAME+']

        SELECT @NEWID,''INSERT'',* FROM inserted

        SET @ROWCOUNT=@@ROWCOUNT

    END

    --==============================记录日志和回滚操作的SQL===========================

    --******************生成插入语句用到的列名(需避开自增字段)********************

    DECLARE @COLUMN1 NVARCHAR(MAX)=''''

    SELECT @COLUMN1+='',[''+COLUMN_NAME+'']'' FROM INFORMATION_SCHEMA.columns

    WHERE TABLE_NAME='''+@TABLENAME+'''

    AND COLUMNPROPERTY(OBJECT_ID('''+@TABLENAME+'''),COLUMN_NAME,''IsIdentity'')<>1 --非自增字段

    SET @COLUMN1=SUBSTRING(@COLUMN1,2,LEN(@COLUMN1))

    --*******************动态定义变量、删除条件匹配的列********************

    DECLARE @DECLARE VARCHAR(MAX)='''',@INTODECLARE VARCHAR(MAX)='''',@WHERE VARCHAR(MAX)='''',@COLUMN2 VARCHAR(MAX)=''''

    SELECT @DECLARE+=''@''+COLUMN_NAME+'' ''+DATA_TYPE+CASE ISNULL(CAST(CHARACTER_OCTET_LENGTH AS VARCHAR(10)),'''') WHEN '''' THEN '','' WHEN ''-1'' THEN ''(MAX),'' ELSE ''(''+CAST(CHARACTER_OCTET_LENGTH AS VARCHAR(10))+''),'' END,

        @INTODECLARE+=''@''+COLUMN_NAME+'','',

        @COLUMN2+=''[''+COLUMN_NAME+''],'' ,

        @WHERE += ''ISNULL(''+ COLUMN_NAME+'','''''''')=ISNULL(@''+COLUMN_NAME+'','''''''') AND ''

    FROM INFORMATION_SCHEMA.columns

    WHERE TABLE_NAME='''+@TABLENAME+'''

    SET @DECLARE=LEFT(@DECLARE,LEN(@DECLARE)-1)

    SET @INTODECLARE=LEFT(@INTODECLARE,LEN(@INTODECLARE)-1)

    SET @COLUMN2=LEFT(@COLUMN2,LEN(@COLUMN2)-1)

    SET @WHERE= LEFT(@WHERE,LEN(@WHERE)-3)

    --*******************判断是否还原当前表的最近一次操作*******************         

    DECLARE @SQL_ISLAST VARCHAR(MAX)=''

    SET NOCOUNT ON

    DECLARE @maxdate datetime

    SELECT @maxdate=max(updatetime) FROM UPDATE_LOG WHERE TableName='''''+@TABLENAME+'''''

    IF NOT EXISTS(SELECT 1 FROM UPDATE_LOG WHERE UpdateTime=@maxdate AND UPDATEGUID=''''''+@NEWID+'''''')

    BEGIN

        DECLARE @MAXGUID VARCHAR(50)

        SELECT @MAXGUID=UPDATEGUID FROM UPDATE_LOG WHERE UpdateTime=@maxdate

        PRINT ''''此操作并非最近一次操作,请逐步还原,此表最近一次操作的GUID是:''''+@MAXGUID

        RETURN

    END

    ''

    --********************还原insert和update操作用到的SQL*******************

    DECLARE @SQL_DELETE VARCHAR(MAX)=''

    SET ROWCOUNT 1  --设定相同条件下只删除1行        

    DECLARE Cursor_ CURSOR FOR

    SELECT ''+@COLUMN2+'' FROM BACKUP_'+@TABLENAME+' WHERE UPDATEGUID= ''''''+@NEWID+'''''' AND UpdateType=''''INSERT''''

    OPEN Cursor_

    DECLARE ''+@DECLARE+''

    FETCH NEXT FROM Cursor_ INTO ''+@INTODECLARE+''

    WHILE @@FETCH_STATUS=0

    BEGIN                  

        DELETE FROM '+@TABLENAME+' WHERE ''+@WHERE+''

        FETCH NEXT FROM Cursor_ INTO ''+@INTODECLARE+''

    END

    CLOSE Cursor_

    DEALLOCATE Cursor_

    SET ROWCOUNT 0

    ''

    --*********************还原delete和update操作用到的SQL*******************

    DECLARE @SQL_INSERT VARCHAR(MAX)=''

    INSERT INTO '+@TABLENAME+' SELECT ''+@COLUMN1+'' FROM BACKUP_'+@TABLENAME+' WHERE UPDATEGUID=''''''+@NEWID+'''''' AND UpdateType=''''DELETE''''

    ''

    --*********************还原操作之后把备份表和log表的记录删掉*************

    DECLARE @SQL_DELGUID VARCHAR(MAX)=''

    DELETE FROM BACKUP_'+@TABLENAME+' WHERE  UPDATEGUID IN(SELECT UPDATEGUID FROM UPDATE_LOG WHERE UpdateTime>=@maxdate AND TableName='''''+@TABLENAME+''''')

    DELETE FROM UPDATE_LOG WHERE UpdateTime>=@maxdate AND TableName='''''+@TABLENAME+'''''

    PRINT ''''回滚操作执行成功,共恢复 ''+CAST(@ROWCOUNT AS VARCHAR(10))+'' 条记录''''

    SET NOCOUNT OFF

    ''

    --*********************执行还原操作的SQL**********************************

    DECLARE @EXECSQL VARCHAR(500)=''

    DECLARE @SQL VARCHAR(MAX)

    SELECT @SQL=ROLLBACKSQL FROM UPDATE_LOG WHERE UPDATEGUID=''''''+@NEWID+''''''  

    EXEC(@SQL) 

    ''

    --==============================判断执行的哪种操作方式=================================

    DECLARE @DoType VARCHAR(MAX)=''UPDATE''

    IF NOT EXISTS(SELECT 1 FROM deleted)

        SET @DoType=''INSERT''

    IF NOT EXISTS(SELECT 1 FROM inserted)

        SET @DoType=''DELETE''

    IF NOT EXISTS(SELECT 1 FROM deleted) AND  NOT EXISTS(SELECT 1 FROM inserted)

        RETURN

    IF @DoType=''UPDATE''

    BEGIN

        INSERT INTO [dbo].[UPDATE_LOG]

        SELECT @NEWID,GETDATE(),'''+@TABLENAME+''',''UPDATE'',@SQL_ISLAST+@SQL_DELETE+@SQL_INSERT+@SQL_DELGUID,@EXECSQL

        RETURN

    END

    IF @DoType=''DELETE''

    BEGIN

        INSERT INTO [dbo].[UPDATE_LOG]

        SELECT @NEWID,GETDATE(),'''+@TABLENAME+''',''DELETE'',@SQL_ISLAST+@SQL_INSERT+@SQL_DELGUID,@EXECSQL

        RETURN

    END

    IF @DoType=''INSERT''

    BEGIN

        INSERT INTO [dbo].[UPDATE_LOG]

        SELECT @NEWID,GETDATE(),'''+@TABLENAME+''',''INSERT'',@SQL_ISLAST+@SQL_DELETE+@SQL_DELGUID,@EXECSQL

        RETURN

    END

END

            '

        EXEC (@SQLTR)

    END

END

  

SQL SERVER回滚恢复误操作的数据的更多相关文章

  1. SQL server基础知识(表操作、数据约束、多表链接查询)

    SQL server基础知识 一.基础知识 (1).存储结构:数据库->表->数据 (2).管理数据库 增加:create database 数据库名称 删除:drop database ...

  2. Git误操作 git reset强制回滚 恢复commit方法

    参考: 找回Git中丢失的Commit Git误操作 git reset强制回滚 恢复commit方法 使用Git时,常有误操作,在Commit之后又执行了git reset --hard HEAD强 ...

  3. 转 一篇关于sql server 三种恢复模式的文章,从sql server 的机制上来写的,感觉很不错,转了

    简介 SQL Server中的事务日志无疑是SQL Server中最重要的部分之一.因为SQL SERVER利用事务日志来确保持久性(Durability)和事务回滚(Rollback).从而还部分确 ...

  4. SQL Server的实例恢复解析

    同Oracle一样,SQL Server在非一致性关闭的时候也会进行实例恢复(Instance Recovery),本文根据stack overflow的文章介绍一些SQL Server实例恢复的知识 ...

  5. 【转】mysql触发器的实战(触发器执行失败,sql会回滚吗)

    1   引言Mysql的触发器和存储过程一样,都是嵌入到mysql的一段程序.触发器是mysql5新增的功能,目前线上凤巢系统.北斗系统以及哥伦布系统使用的数据库均是mysql5.0.45版本,很多程 ...

  6. SQL Server数据库有三种恢复模式:简单恢复模式、完整恢复模式和大容量日志恢复模式

    SQL Server数据库有三种恢复模式:简单恢复模式.完整恢复模式和大容量日志恢复模式: 1.Simple 简单恢复模式, Simple模式的旧称叫”Checkpoint with truncate ...

  7. [SQL Server]数据库的恢复

    数据库恢复是和数据库备份相对应的操作,它是将数据库备份重新加载到系统中的过程.数据库恢复可以创建备份完成时数据库中存在的相关文件,但是备份以后的所有数据库修改都将丢失. SQL Server进行数据库 ...

  8. SQL Server 索引的图形界面操作 <第十二篇>

    一.索引的图形界面操作 SQL Server非常强大的就是图形界面操作.关于索引方面也一样那么强大,很多操作比如说重建索引啊,查看各种统计信息啊,都能够通过图形界面快速查看和操作,下面来看看SQL S ...

  9. 从SQL Server到MySQL,近百亿数据量迁移实战

    从SQL Server到MySQL,近百亿数据量迁移实战 狄敬超(3D) 2018-05-29 10:52:48 212 沪江成立于 2001 年,作为较早期的教育学习网站,当时技术选型范围并不大:J ...

随机推荐

  1. 微信小程序代码片段

    微信小程序代码片段是一种可分享的小项目,可用于分享小程序和小游戏的开发经验.展示组件和 API 的使用.复现开发问题等等.分享代码片段会得到一个链接,所有拥有此分享链接的人可以在工具中导入此代码片段. ...

  2. Zabbix3.4-部署安装

    Zabbix部署安装: 系统环境:CentOS 7 Zabbix版本:Zabbix 3.4 关闭防火墙和SELINUX systemctl stop firewalld && sete ...

  3. VC++ 6.0 C8051F340 USB 通信 CAN 数据解析

    // HelloWorld.cpp : Defines the entry point for the console application. // /*********************** ...

  4. 一步步入门log4cpp

    前言 项目实现过程中,需要检查.查找或者调试程序bug等,此时程序日志则较为清晰地展现代码的运行过程.目前接触到的方法有打印消息到控制台,将重要信息输出到某个文件比如txt文件,或者直接使用日志库. ...

  5. Vue实现刷新当前路由

    Vue点击当前路由实现刷新 Vue点击当前路由实现刷新思路Code实现效果 前言:在后台管理系统中,有这样一个需求点击当前菜单栏时,页面依旧可以刷新. 点击当前路由实现数据请求页面刷新 思路 点击当前 ...

  6. 服务器购买+建站流程教程——适合新手没有经验的人Chinar总结

    服务器购买购买教程 本文提供全图文流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创 ...

  7. 在windows下制作mac os x的启动安装U盘

    前几天有幸用了下Macbook pro,可在给它装win 7系统时,无知而又手贱地在windows系统下分区了:( 然后再重启就找不到Mac os x,只有win 7了.可进win 7也不正常,直接给 ...

  8. 《DSP using MATLAB》Problem 4.14

    代码: %% ---------------------------------------------------------------------------- %% Output Info a ...

  9. ThinkPHP AJAX分页及JS缓存的应用

    //AJAX分页详见兄弟连PHP项目视频教程22讲35分钟左右 主要实现是需要将分页中的每个链接都改为AJAX请求 //前端缓存技术:基于javascript传输的数据,只要浏览器没关,都保存在内存中 ...

  10. 【maven】Maven中的dependencyManagement

    dependencyManagement使用简介 Maven中的dependencyManagement元素提供了一种管理依赖版本号的方式.在dependencyManagement元素中声明所依赖的 ...