zoukankan      html  css  js  c++  java
  • 转 --- 恢复误删数据

    曾经想实现Log Explorer for SQL Server的功能,利用ldf里面的日志来还原误删除的数据

    这里有一篇文章做到了,不过似乎不是所有的数据类型都支持

    以下为译文:http://raresql.com/2011/10/22/how-to-recover-deleted-data-from-sql-sever/

    在我使用SQLSERVER的这些年里面,大部分人都会问我一个问题:“能不能恢复被删除的数据??”

    现在,从SQLSERVER2005 或以上版本能很容易能够恢复被删除的数据

    (注意:这个脚本能恢复下面的数据类型的数据 而且兼容CS 排序规则)

    • image
    • text
    • uniqueidentifier
    • tinyint
    • smallint
    • int
    • smalldatetime
    • real
    • money
    • datetime
    • float
    • sql_variant
    • ntext
    • bit
    • decimal
    • numeric
    • smallmoney
    • bigint
    • varbinary
    • varchar
    • binary
    • char
    • timestamp
    • nvarchar
    • nchar
    • xml
    • sysname

    让我来用demo来解释一下我是怎么做到的

    USE master
    GO--创建数据库CREATEDATABASE test
    GOUSE[test]GO--创建表CREATETABLE[dbo].[aa](
        [id][int]IDENTITY(1,1) NOTNULL,
        [NAME][nvarchar](200) NULL
    ) ON[PRIMARY]GO--插入测试数据INSERT[dbo].[aa]
            ( [NAME] )
    SELECT'你好'GO--删除数据Deletefrom aa
    Go--验证数据是否已经删除Select*from aa
    Go

    现在你需要创建一个存储过程来恢复你的数据

    -- Script Name: Recover_Deleted_Data_Proc
    -- Script Type : Recovery Procedure 
    -- Develop By: Muhammad Imran
    -- Date Created: 15 Oct 2011
    -- Modify Date: 22 Aug 2012
    -- Version    : 3.1
    -- Notes : Included BLOB data types for recovery.& Compatibile with Default , CS collation , Arabic_CI_AS.CREATEPROCEDURE Recover_Deleted_Data_Proc
        @Database_NameNVARCHAR(MAX) ,
        @SchemaName_n_TableNameNVARCHAR(MAX) ,
        @Date_FromDATETIME='1900/01/01' ,
        @Date_ToDATETIME='9999/12/31'ASDECLARE@RowLogContentsVARBINARY(8000)
        DECLARE@TransactionIDNVARCHAR(MAX)
        DECLARE@AllocUnitIDBIGINTDECLARE@AllocUnitNameNVARCHAR(MAX)
        DECLARE@SQLNVARCHAR(MAX)
        DECLARE@Compatibility_LevelINTSELECT@Compatibility_Level= dtb.compatibility_level
        FROM    master.sys.databases AS dtb
        WHERE   dtb.name =@Database_NameIFISNULL(@Compatibility_Level, 0) <=80BEGINRAISERROR('The compatibility level should be equal to or greater SQL SERVER 2005 (90)',16,1)
                RETURNENDIF ( SELECTCOUNT(*)
             FROM   INFORMATION_SCHEMA.TABLES
             WHERE[TABLE_SCHEMA]+'.'+[TABLE_NAME]=@SchemaName_n_TableName
           ) =0BEGINRAISERROR('Could not found the table in the defined database',16,1)
                RETURNENDDECLARE@bitTableTABLE
            (
              [ID]INT ,
              [Bitvalue]INT
            )
    --Create table to set the bit position of one byte.INSERTINTO@bitTableSELECT0 ,
                        2UNIONALLSELECT1 ,
                        2UNIONALLSELECT2 ,
                        4UNIONALLSELECT3 ,
                        8UNIONALLSELECT4 ,
                        16UNIONALLSELECT5 ,
                        32UNIONALLSELECT6 ,
                        64UNIONALLSELECT7 ,
                        128--Create table to collect the row data.DECLARE@DeletedRecordsTABLE
            (
              [Row ID]INTIDENTITY(1, 1) ,
              [RowLogContents]VARBINARY(8000) ,
              [AllocUnitID]BIGINT ,
              [Transaction ID]NVARCHAR(MAX) ,
              [FixedLengthData]SMALLINT ,
              [TotalNoOfCols]SMALLINT ,
              [NullBitMapLength]SMALLINT ,
              [NullBytes]VARBINARY(8000) ,
              [TotalNoofVarCols]SMALLINT ,
              [ColumnOffsetArray]VARBINARY(8000) ,
              [VarColumnStart]SMALLINT ,
              [Slot ID]INT ,
              [NullBitMap]VARCHAR(MAX)
            )
    --Create a common table expression to get all the row data plus how many bytes we have for each row.;
        WITH    RowData
                  AS ( SELECT[RowLog Contents 0]AS[RowLogContents] ,
                                [AllocUnitID]AS[AllocUnitID] ,
                                [Transaction ID]AS[Transaction ID]--[Fixed Length Data] = Substring (RowLog content 0, Status Bit A+ Status Bit B + 1,2 bytes)                            ,
                                CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) AS[FixedLengthData]--@FixedLengthData-- [TotalnoOfCols] =  Substring (RowLog content 0, [Fixed Length Data] + 1,2 bytes)                            ,
                                CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) AS[TotalNoOfCols]--[NullBitMapLength]=ceiling([Total No of Columns] /8.0)                            ,
                                CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) /8.0)) AS[NullBitMapLength]--[Null Bytes] = Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [NullBitMapLength] )                            ,
                                SUBSTRING([RowLog Contents 0],
                                          CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +3,
                                          CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) /8.0))) AS[NullBytes]--[TotalNoofVarCols] = Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 )                            ,
                                ( CASEWHENSUBSTRING([RowLog Contents 0], 1, 1) IN (
                                            0x10, 0x30, 0x70 )
                                       THENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +3+CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) /8.0)), 2))))
                                       ELSENULLEND ) AS[TotalNoofVarCols]--[ColumnOffsetArray]= Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 , [TotalNoofVarCols]*2 )                            ,
                                ( CASEWHENSUBSTRING([RowLog Contents 0], 1, 1) IN (
                                            0x10, 0x30, 0x70 )
                                       THENSUBSTRING([RowLog Contents 0],
                                                      CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +3+CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) /8.0))
                                                      +2,
                                                      ( CASEWHENSUBSTRING([RowLog Contents 0],
                                                                  1, 1) IN ( 0x10,
                                                                  0x30, 0x70 )
                                                             THENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +3+CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) /8.0)), 2))))
                                                             ELSENULLEND ) *2)
                                       ELSENULLEND ) AS[ColumnOffsetArray]--  Variable column Start = Status Bit A+ Status Bit B + [Fixed Length Data] + [Null Bitmap length] + 2+([TotalNoofVarCols]*2)                            ,
                                CASEWHENSUBSTRING([RowLog Contents 0], 1, 1) IN (
                                          0x10, 0x30, 0x70 )
                                     THEN ( CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +4+CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) /8.0))
                                            + ( ( CASEWHENSUBSTRING([RowLog Contents 0],
                                                                  1, 1) IN ( 0x10,
                                                                  0x30, 0x70 )
                                                       THENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +3+CONVERT(INT, CEILING(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  2+1, 2)))) +1,
                                                                  2)))) /8.0)), 2))))
                                                       ELSENULLEND ) *2 ) )
                                     ELSENULLENDAS[VarColumnStart] ,
                                [Slot ID]FROM     sys.fn_dblog(NULL, NULL)
                       WHERE    AllocUnitId IN (
                                SELECT[Allocation_unit_id]FROM    sys.allocation_units allocunits
                                        INNERJOIN sys.partitions partitions ON ( allocunits.type IN (
                                                                  1, 3 )
                                                                  AND partitions.hobt_id = allocunits.container_id
                                                                  )
                                                                  OR ( allocunits.type =2AND partitions.partition_id = allocunits.container_id
                                                                  )
                                WHEREobject_id=OBJECT_ID(''+@SchemaName_n_TableName+'') )
                                AND Context IN ( 'LCX_MARK_AS_GHOST', 'LCX_HEAP' )
                                AND Operation IN ( 'LOP_DELETE_ROWS' )
                                ANDSUBSTRING([RowLog Contents 0], 1, 1) IN ( 0x10,
                                                                  0x30, 0x70 )
     
    /*Use this subquery to filter the date*/AND[TRANSACTION ID]IN (
                                SELECTDISTINCT[TRANSACTION ID]FROM    sys.fn_dblog(NULL, NULL)
                                WHERE   Context IN ( 'LCX_NULL' )
                                        AND Operation IN ( 'LOP_BEGIN_XACT' )
                                        AND[Transaction Name]IN ( 'DELETE',
                                                                  'user_transaction' )
                                        ANDCONVERT(NVARCHAR(11), [Begin Time]) BETWEEN@Date_FromAND@Date_To )
                     ),
     
    --Use this technique to repeate the row till the no of bytes of the row.            N1 ( n )
                  AS ( SELECT1UNIONALLSELECT1
                     ),
                N2 ( n )
                  AS ( SELECT1FROM     N1 AS X ,
                                N1 AS Y
                     ),
                N3 ( n )
                  AS ( SELECT1FROM     N2 AS X ,
                                N2 AS Y
                     ),
                N4 ( n )
                  AS ( SELECT   ROW_NUMBER() OVER ( ORDERBY X.n )
                       FROM     N3 AS X ,
                                N3 AS Y
                     )
            INSERTINTO@DeletedRecordsSELECT  RowLogContents ,
                            [AllocUnitID] ,
                            [Transaction ID] ,
                            [FixedLengthData] ,
                            [TotalNoOfCols] ,
                            [NullBitMapLength] ,
                            [NullBytes] ,
                            [TotalNoofVarCols] ,
                            [ColumnOffsetArray] ,
                            [VarColumnStart] ,
                            [Slot ID]---Get the Null value against each column (1 means null zero means not null)                        ,
                            [NullBitMap]= ( REPLACE(STUFF(( SELECT','+ ( CASEWHEN[ID]=0THENCONVERT(NVARCHAR(1), ( SUBSTRING(NullBytes,
                                                                  n, 1) %2 ))
                                                                  ELSECONVERT(NVARCHAR(1), ( ( SUBSTRING(NullBytes,
                                                                  n, 1)
                                                                  /[Bitvalue] )
                                                                  %2 ))
                                                                  END ) --as [nullBitMap]FROM N4 AS Nums
                                                                  JOIN RowData AS C ON n <= NullBitMapLength
                                                                  CROSSJOIN@bitTableWHERE
                                                                  C.[RowLogContents]= D.[RowLogContents]ORDERBY[RowLogContents] ,
                                                                  n ASCFOR
                                                             XML PATH('')
                                                           ), 1, 1, ''), ',', '') )
                    FROM    RowData D
     
        IF ( SELECTCOUNT(*)
             FROM@DeletedRecords
           ) =0BEGINRAISERROR('There is no data in the log as per the search criteria',16,1)
                RETURNENDDECLARE@ColumnNameAndDataTABLE
            (
              [Row ID]INT ,
              [Rowlogcontents]VARBINARY(MAX) ,
              [NAME] SYSNAME ,
              [nullbit]SMALLINT ,
              [leaf_offset]SMALLINT ,
              [length]SMALLINT ,
              [system_type_id]TINYINT ,
              [bitpos]TINYINT ,
              [xprec]TINYINT ,
              [xscale]TINYINT ,
              [is_null]INT ,
              [Column value Size]INT ,
              [Column Length]INT ,
              [hex_Value]VARBINARY(MAX) ,
              [Slot ID]INT ,
              [Update]INT
            )
     
    --Create common table expression and join it with the rowdata table
    -- to get each column details
    /*This part is for variable data columns*/--@RowLogContents, 
    --(col.columnOffValue - col.columnLength) + 1,
    --col.columnLength
    --)INSERTINTO@ColumnNameAndDataSELECT[Row ID] ,
                        Rowlogcontents ,
                        NAME ,
                        cols.leaf_null_bit AS nullbit ,
                        leaf_offset ,
                        ISNULL(syscolumns.length, cols.max_length) AS[length] ,
                        cols.system_type_id ,
                        cols.leaf_bit_position AS bitpos ,
                        ISNULL(syscolumns.xprec, cols.precision) AS xprec ,
                        ISNULL(syscolumns.xscale, cols.scale) AS xscale ,
                        SUBSTRING([nullBitMap], cols.leaf_null_bit, 1) AS is_null ,
                        ( CASEWHEN leaf_offset <1ANDSUBSTRING([nullBitMap], cols.leaf_null_bit,
                                                  1) =0THEN ( CASEWHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000THENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                -POWER(2, 15)
                                           ELSECONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                      END )
                          END ) AS[Column value Size] ,
                        ( CASEWHEN leaf_offset <1ANDSUBSTRING([nullBitMap], cols.leaf_null_bit,
                                                  1) =0THEN ( CASEWHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                           [varColumnStart]) <30000THEN ( CASEWHEN[System_type_id]IN (
                                                            35, 34, 99 ) THEN16ELSE24END )
                                           WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                           [varColumnStart]) >30000THEN ( CASEWHEN[System_type_id]IN (
                                                            35, 34, 99 ) THEN16ELSE24END ) --24 WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) <30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                           [varColumnStart]) <30000THEN ( CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                  -ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                           [varColumnStart]) )
                                           WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) <30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                           [varColumnStart]) >30000THENPOWER(2, 15)
                                                +CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                -ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                         [varColumnStart])
                                      END )
                          END ) AS[Column Length] ,
                        ( CASEWHENSUBSTRING([nullBitMap], cols.leaf_null_bit, 1) =1THENNULLELSESUBSTRING(Rowlogcontents,
                                              ( ( CASEWHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000THENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                            -POWER(2, 15)
                                                       ELSECONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                  END )
                                                - ( CASEWHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) <30000THEN ( CASEWHEN[System_type_id]IN (
                                                                  35, 34, 99 )
                                                                  THEN16ELSE24END ) --24 WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) >30000THEN ( CASEWHEN[System_type_id]IN (
                                                                  35, 34, 99 )
                                                                  THEN16ELSE24END ) --24 WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) <30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) <30000THENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                              -ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart])
                                                         WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) <30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) >30000THENPOWER(2, 15)
                                                              +CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                              -ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart])
                                                    END ) ) +1,
                                              ( CASEWHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) <30000THEN ( CASEWHEN[System_type_id]IN (
                                                                  35, 34, 99 )
                                                                 THEN16ELSE24END ) --24 WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) >30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) >30000THEN ( CASEWHEN[System_type_id]IN (
                                                                  35, 34, 99 )
                                                                 THEN16ELSE24END ) --24 WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) <30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) <30000THENABS(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                              -ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]))
                                                     WHENCONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2)))) <30000ANDISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart]) >30000THENPOWER(2, 15)
                                                          +CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* leaf_offset
                                                                  *-1 ) -1, 2))))
                                                          -ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],
                                                                  ( 2* ( ( leaf_offset
                                                                  *-1 ) -1 ) )
                                                                  -1, 2)))), 0),
                                                                  [varColumnStart])
                                                END ))
                          END ) AS hex_Value ,
                        [Slot ID] ,
                        0FROM@DeletedRecords A
                        INNERJOIN sys.allocation_units allocunits ON A.[AllocUnitId]= allocunits.[Allocation_Unit_Id]INNERJOIN sys.partitions partitions ON ( allocunits.type IN (
                                                                  1, 3 )
                                                                  AND partitions.hobt_id = allocunits.container_id
                                                                )
                                                                OR ( allocunits.type =2AND partitions.partition_id = allocunits.container_id
                                                                  )
                        INNERJOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_id
                        LEFTOUTERJOIN syscolumns ON syscolumns.id = partitions.object_idAND syscolumns.colid = cols.partition_column_id
                WHERE   leaf_offset <0UNION/*This part is for fixed data columns*/SELECT[Row ID] ,
                        Rowlogcontents ,
                        NAME ,
                        cols.leaf_null_bit AS nullbit ,
                        leaf_offset ,
                        ISNULL(syscolumns.length, cols.max_length) AS[length] ,
                        cols.system_type_id ,
                        cols.leaf_bit_position AS bitpos ,
                        ISNULL(syscolumns.xprec, cols.precision) AS xprec ,
                        ISNULL(syscolumns.xscale, cols.scale) AS xscale ,
                        SUBSTRING([nullBitMap], cols.leaf_null_bit, 1) AS is_null ,
                        ( SELECTTOP1ISNULL(SUM(CASEWHEN C.leaf_offset >1THEN max_length
                                                    ELSE0END), 0)
                          FROM      sys.system_internals_partition_columns C
                          WHERE     cols.partition_id = C.partition_id
                                    AND C.leaf_null_bit < cols.leaf_null_bit
                        ) +5AS[Column value Size] ,
                        syscolumns.length AS[Column Length] ,
                        CASEWHENSUBSTRING([nullBitMap], cols.leaf_null_bit, 1) =1THENNULLELSESUBSTRING(Rowlogcontents,
                                            ( SELECTTOP1ISNULL(SUM(CASEWHEN C.leaf_offset >1AND C.leaf_bit_position =0THEN max_length
                                                                  ELSE0END), 0)
                                              FROM      sys.system_internals_partition_columns C
                                              WHERE     cols.partition_id = C.partition_id
                                                        AND C.leaf_null_bit < cols.leaf_null_bit
                                            ) +5, syscolumns.length)
                        ENDAS hex_Value ,
                        [Slot ID] ,
                        0FROM@DeletedRecords A
                        INNERJOIN sys.allocation_units allocunits ON A.[AllocUnitId]= allocunits.[Allocation_Unit_Id]INNERJOIN sys.partitions partitions ON ( allocunits.type IN (
                                                                  1, 3 )
                                                                  AND partitions.hobt_id = allocunits.container_id
                                                                )
                                                                OR ( allocunits.type =2AND partitions.partition_id = allocunits.container_id
                                                                  )
                        INNERJOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_id
                        LEFTOUTERJOIN syscolumns ON syscolumns.id = partitions.object_idAND syscolumns.colid = cols.partition_column_id
                WHERE   leaf_offset >0ORDERBY nullbit
     
        DECLARE@BitColumnByteASINTSELECT@BitColumnByte=CONVERT(INT, CEILING(COUNT(*) /8.0))
        FROM@ColumnNameAndDataWHERE[System_Type_id]=104;
        WITH    N1 ( n )
                  AS ( SELECT1UNIONALLSELECT1
                     ),
                N2 ( n )
                  AS ( SELECT1FROM     N1 AS X ,
                                N1 AS Y
                     ),
                N3 ( n )
                  AS ( SELECT1FROM     N2 AS X ,
                                N2 AS Y
                     ),
                N4 ( n )
                  AS ( SELECT   ROW_NUMBER() OVER ( ORDERBY X.n )
                       FROM     N3 AS X ,
                                N3 AS Y
                     ),
                CTE
                  AS ( SELECT   RowLogContents ,
                                [nullbit] ,
                                [BitMap]=CONVERT(VARBINARY(1), CONVERT(INT, SUBSTRING(( REPLACE(STUFF(( SELECT','+ ( CASEWHEN[ID]=0THENCONVERT(NVARCHAR(1), ( SUBSTRING(hex_Value,
                                                                  n, 1) %2 ))
                                                                  ELSECONVERT(NVARCHAR(1), ( ( SUBSTRING(hex_Value,
                                                                  n, 1)
                                                                  /[Bitvalue] )
                                                                  %2 ))
                                                                  END ) --as [nullBitMap]FROM
                                                                  N4 AS Nums
                                                                  JOIN@ColumnNameAndDataAS C ON n <=@BitColumnByteAND[System_Type_id]=104AND bitpos =0CROSSJOIN@bitTableWHERE
                                                                  C.[RowLogContents]= D.[RowLogContents]ORDERBY[RowLogContents] ,
                                                                  n ASCFOR
                                                                  XML
                                                                  PATH('')
                                                                  ), 1, 1, ''),
                                                                  ',', '') ),
                                                                  bitpos +1, 1)))
                       FROM@ColumnNameAndData D
                       WHERE[System_Type_id]=104
                     )
            UPDATE  A
            SET[hex_Value]=[BitMap]FROM@ColumnNameAndData A
                    INNERJOIN CTE B ON A.[RowLogContents]= B.[RowLogContents]AND A.[nullbit]= B.[nullbit]/**************Check for BLOB DATA TYPES******************************/DECLARE@FileidINTDECLARE@PageidINTDECLARE@SlotidINTDECLARE@CurrentLSNINTDECLARE@LinkIDINTDECLARE@ContextVARCHAR(50)
        DECLARE@ConsolidatedPageIDVARCHAR(MAX)
        DECLARE@LCX_TEXT_MIXVARBINARY(MAX)
     
        DECLARE@temppagedataTABLE
            (
              [ParentObject] SYSNAME ,
              [Object] SYSNAME ,
              [Field] SYSNAME ,
              [Value] SYSNAME
            )
     
        DECLARE@pagedataTABLE
            (
              [Page ID] SYSNAME ,
              [File IDS]INT ,
              [Page IDS]INT ,
              [AllocUnitId]BIGINT ,
              [ParentObject] SYSNAME ,
              [Object] SYSNAME ,
              [Field] SYSNAME ,
              [Value] SYSNAME
            )
     
        DECLARE@ModifiedRawDataTABLE
            (
              [ID]INTIDENTITY(1, 1) ,
              [PAGE ID]VARCHAR(MAX) ,
              [FILE IDS]INT ,
              [PAGE IDS]INT ,
              [Slot ID]INT ,
              [AllocUnitId]BIGINT ,
              [RowLog Contents 0_var]VARCHAR(MAX) ,
              [RowLog Length]VARCHAR(50) ,
              [RowLog Len]INT ,
              [RowLog Contents 0]VARBINARY(MAX) ,
              [Link ID]INTDEFAULT ( 0 ) ,
              [Update]INT
            )
     
        DECLARE Page_Data_Cursor CURSORFOR/*We need to filter LOP_MODIFY_ROW,LOP_MODIFY_COLUMNS from log for deleted records of BLOB data type& Get its Slot No, Page ID & AllocUnit ID*/SELECTLTRIM(RTRIM(REPLACE([Description], 'Deallocated', ''))) AS[PAGE ID] ,
                        [Slot ID] ,
                        [AllocUnitId] ,
                        NULLAS[RowLog Contents 0] ,
                        NULLAS[RowLog Contents 0] ,
                        Context
                FROM    sys.fn_dblog(NULL, NULL)
                WHERE   AllocUnitId IN (
                        SELECT[Allocation_unit_id]FROM    sys.allocation_units allocunits
                                INNERJOIN sys.partitions partitions ON ( allocunits.type IN (
                                                                  1, 3 )
                                                                  AND partitions.hobt_id = allocunits.container_id
                                                                  )
                                                                  OR ( allocunits.type =2AND partitions.partition_id = allocunits.container_id
                                                                  )
                        WHEREobject_id=OBJECT_ID(''+@SchemaName_n_TableName+'') )
                        AND Operation IN ( 'LOP_MODIFY_ROW' )
                        AND[Context]IN ( 'LCX_PFS' )
                        AND Description LIKE'%Deallocated%'/*Use this subquery to filter the date*/AND[TRANSACTION ID]IN (
                        SELECTDISTINCT[TRANSACTION ID]FROM    sys.fn_dblog(NULL, NULL)
                        WHERE   Context IN ( 'LCX_NULL' )
                                AND Operation IN ( 'LOP_BEGIN_XACT' )
                                AND[Transaction Name]='DELETE'ANDCONVERT(NVARCHAR(11), [Begin Time]) BETWEEN@Date_FromAND@Date_To )
                GROUPBY[Description] ,
                        [Slot ID] ,
                        [AllocUnitId] ,
                        Context
                UNIONSELECT[PAGE ID] ,
                        [Slot ID] ,
                        [AllocUnitId] ,
                        SUBSTRING([RowLog Contents 0], 15,
                                  LEN([RowLog Contents 0])) AS[RowLog Contents 0] ,
                        CONVERT(INT, SUBSTRING([RowLog Contents 0], 7, 2)) ,
                        Context --,CAST(RIGHT([Current LSN],4) AS INT) AS [Current LSN]FROM    sys.fn_dblog(NULL, NULL)
                WHERE   AllocUnitId IN (
                        SELECT[Allocation_unit_id]FROM    sys.allocation_units allocunits
                                INNERJOIN sys.partitions partitions ON ( allocunits.type IN (
                                                                  1, 3 )
                                                                  AND partitions.hobt_id = allocunits.container_id
                                                                  )
                                                                  OR ( allocunits.type =2AND partitions.partition_id = allocunits.container_id
                                                                  )
                        WHEREobject_id=OBJECT_ID(''+@SchemaName_n_TableName+'') )
                        AND Context IN ( 'LCX_TEXT_MIX' )
                        AND Operation IN ( 'LOP_DELETE_ROWS' ) 
                /*Use this subquery to filter the date*/AND[TRANSACTION ID]IN (
                        SELECTDISTINCT[TRANSACTION ID]FROM    sys.fn_dblog(NULL, NULL)
                        WHERE   Context IN ( 'LCX_NULL' )
                                AND Operation IN ( 'LOP_BEGIN_XACT' )
                                AND[Transaction Name]='DELETE'ANDCONVERT(NVARCHAR(11), [Begin Time]) BETWEEN@Date_FromAND@Date_To )
                             
                /****************************************/OPEN Page_Data_Cursor
     
        FETCHNEXTFROM Page_Data_Cursor INTO@ConsolidatedPageID, @Slotid,
            @AllocUnitID, @LCX_TEXT_MIX, @LinkID, @ContextWHILE@@FETCH_STATUS=0BEGINDECLARE@hex_pageidASVARCHAR(MAX)
                /*Page ID contains File Number and page number It looks like 0001:00000130.
                  In this example 0001 is file Number &  00000130 is Page Number & These numbers are in Hex format*/SET@Fileid=SUBSTRING(@ConsolidatedPageID, 0,
                                        CHARINDEX(':', @ConsolidatedPageID)) -- Seperate File ID from Page IDSET@hex_pageid='0x'+SUBSTRING(@ConsolidatedPageID,
                                                   CHARINDEX(':',
                                                             @ConsolidatedPageID)
                                                   +1, LEN(@ConsolidatedPageID))  ---Seperate the page IDSELECT@Pageid=CONVERT(INT, CAST(''AS XML).value('xs:hexBinary(substring(sql:variable("@hex_pageid"),sql:column("t.pos")) )',
                                                                  'varbinary(max)')) -- Convert Page ID from hex to integerFROM    ( SELECTCASESUBSTRING(@hex_pageid, 1, 2)
                                      WHEN'0x'THEN3ELSE0END
                        ) AS t ( pos ) 
                 
                IF@Context='LCX_PFS'BEGINDELETE@temppagedataINSERTINTO@temppagedataEXEC
                                    ( 'DBCC PAGE('+@DataBase_Name+', '+@fileid+', '+@pageid+', 1) with tableresults,no_infomsgs;'
                                    ); 
                        INSERTINTO@pagedataSELECT@ConsolidatedPageID ,
                                        @fileid ,
                                        @pageid ,
                                        @AllocUnitID ,
                                        [ParentObject] ,
                                        [Object] ,
                                        [Field] ,
                                        [Value]FROM@temppagedataENDELSEIF@Context='LCX_TEXT_MIX'BEGININSERTINTO@ModifiedRawDataSELECT@ConsolidatedPageID ,
                                            @fileid ,
                                            @pageid ,
                                            @Slotid ,
                                            @AllocUnitID ,
                                            NULL ,
                                            0 ,
                                            CONVERT(INT, CONVERT(VARBINARY, REVERSE(SUBSTRING(@LCX_TEXT_MIX,
                                                                  11, 2)))) ,
                                            @LCX_TEXT_MIX ,
                                            @LinkID ,
                                            0ENDFETCHNEXTFROM Page_Data_Cursor INTO@ConsolidatedPageID, @Slotid,
                    @AllocUnitID, @LCX_TEXT_MIX, @LinkID, @ContextENDCLOSE Page_Data_Cursor
        DEALLOCATE Page_Data_Cursor
     
        DECLARE@NewhexstringVARCHAR(MAX);
     
        --The data is in multiple rows in the page, so we need to convert it into one row as a single hex value.--This hex value is in string formatINSERTINTO@ModifiedRawData
                ( [PAGE ID] ,
                  [FILE IDS] ,
                  [PAGE IDS] ,
                  [Slot ID] ,
                  [AllocUnitId] ,
                  [RowLog Contents 0_var] ,
                  [RowLog Length]
                )
                SELECT[Page ID] ,
                        [FILE IDS] ,
                        [PAGE IDS] ,
                        SUBSTRING([ParentObject],
                                  CHARINDEX('Slot', [ParentObject]) +4,
                                  ( CHARINDEX('Offset', [ParentObject])
                                    - ( CHARINDEX('Slot', [ParentObject]) +4 ) )
                                  -2) AS[Slot ID] ,
                        [AllocUnitId] ,
                        SUBSTRING(( SELECTREPLACE(STUFF(( SELECTREPLACE(SUBSTRING([Value],
                                                                  CHARINDEX(':',
                                                                  [Value]) +1,
                                                                  CHARINDEX('†',
                                                                  [Value])
                                                                  -CHARINDEX(':',
                                                                  [Value])), '†',
                                                                  '')
                                                            FROM@pagedata C
                                                            WHERE B.[Page ID]= C.[Page ID]ANDSUBSTRING(B.[ParentObject],
                                                                  CHARINDEX('Slot',
                                                                  B.[ParentObject])
                                                                  +4,
                                                                  ( CHARINDEX('Offset',
                                                                  B.[ParentObject])
                                                                  - ( CHARINDEX('Slot',
                                                                  B.[ParentObject])
                                                                  +4 ) )) =SUBSTRING(C.[ParentObject],
                                                                  CHARINDEX('Slot',
                                                                  C.[ParentObject])
                                                                  +4,
                                                                  ( CHARINDEX('Offset',
                                                                  C.[ParentObject])
                                                                  - ( CHARINDEX('Slot',
                                                                  C.[ParentObject])
                                                                  +4 ) ))
                                                                  AND[Object]LIKE'%Memory Dump%'ORDERBY'0x'+LEFT([Value],
                                                                  CHARINDEX(':',
                                                                  [Value]) -1)
                                                          FOR
                                                            XML PATH('')
                                                          ), 1, 1, ''), '', '')
                                  ), 1, 20000) AS[Value] ,
                        SUBSTRING(( SELECT'0x'+REPLACE(STUFF(( SELECTREPLACE(SUBSTRING([Value],
                                                                  CHARINDEX(':',
                                                                  [Value]) +1,
                                                                  CHARINDEX('†',
                                                                  [Value])
                                                                  -CHARINDEX(':',
                                                                  [Value])), '†',
                                                                  '')
                                                              FROM@pagedata C
                                                              WHERE
                                                                  B.[Page ID]= C.[Page ID]ANDSUBSTRING(B.[ParentObject],
                                                                  CHARINDEX('Slot',
                                                                  B.[ParentObject])
                                                                  +4,
                                                                  ( CHARINDEX('Offset',
                                                                  B.[ParentObject])
                                                                  - ( CHARINDEX('Slot',
                                                                  B.[ParentObject])
                                                                  +4 ) )) =SUBSTRING(C.[ParentObject],
                                                                  CHARINDEX('Slot',
                                                                  C.[ParentObject])
                                                                  +4,
                                                                  ( CHARINDEX('Offset',
                                                                  C.[ParentObject])
                                                                  - ( CHARINDEX('Slot',
                                                                  C.[ParentObject])
                                                                  +4 ) ))
                                                                  AND[Object]LIKE'%Memory Dump%'ORDERBY'0x'+LEFT([Value],
                                                                  CHARINDEX(':',
                                                                  [Value]) -1)
                                                            FOR
                                                              XML PATH('')
                                                            ), 1, 1, ''), '', '')
                                  ), 7, 4) AS[Length]FROM@pagedata B
                WHERE[Object]LIKE'%Memory Dump%'GROUPBY[Page ID] ,
                        [FILE IDS] ,
                        [PAGE IDS] ,
                        [ParentObject] ,
                        [AllocUnitId]--,[Current LSN]ORDERBY[Slot ID]UPDATE@ModifiedRawDataSET[RowLog Len]=CONVERT(VARBINARY(8000), REVERSE(CAST(''AS XML).value('xs:hexBinary(substring(sql:column("[RowLog Length]"),0))',
                                                                  'varbinary(Max)')))
        FROM@ModifiedRawDataWHERE[LINK ID]=0UPDATE@ModifiedRawDataSET[RowLog Contents 0]=CAST(''AS XML).value('xs:hexBinary(substring(sql:column("[RowLog Contents 0_var]"),0))',
                                                            'varbinary(Max)')
        FROM@ModifiedRawDataWHERE[LINK ID]=0UPDATE  B
        SET     B.[RowLog Contents 0]= ( CASEWHEN A.[RowLog Contents 0]ISNOTNULLAND C.[RowLog Contents 0]ISNOTNULLTHEN A.[RowLog Contents 0]+ C.[RowLog Contents 0]WHEN A.[RowLog Contents 0]ISNULLAND C.[RowLog Contents 0]ISNOTNULLTHEN C.[RowLog Contents 0]WHEN A.[RowLog Contents 0]ISNOTNULLAND C.[RowLog Contents 0]ISNULLTHEN A.[RowLog Contents 0]END ) ,
                B.[Update]=ISNULL(B.[Update], 0) +1FROM@ModifiedRawData B
                LEFTJOIN@ModifiedRawData A ON A.[Page IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  15+14, 2))))
                                                AND A.[File IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  19+14, 2))))
                                                AND A.[Link ID]= B.[Link ID]LEFTJOIN@ModifiedRawData C ON C.[Page IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  27+14, 2))))
                                                AND C.[File IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  31+14, 2))))
                                                AND C.[Link ID]= B.[Link ID]WHERE   ( A.[RowLog Contents 0]ISNOTNULLOR C.[RowLog Contents 0]ISNOTNULL
                )
     
     
        UPDATE  B
        SET     B.[RowLog Contents 0]= ( CASEWHEN A.[RowLog Contents 0]ISNOTNULLAND C.[RowLog Contents 0]ISNOTNULLTHEN A.[RowLog Contents 0]+ C.[RowLog Contents 0]WHEN A.[RowLog Contents 0]ISNULLAND C.[RowLog Contents 0]ISNOTNULLTHEN C.[RowLog Contents 0]WHEN A.[RowLog Contents 0]ISNOTNULLAND C.[RowLog Contents 0]ISNULLTHEN A.[RowLog Contents 0]END )
        --,B.[Update]=ISNULL(B.[Update],0)+1FROM@ModifiedRawData B
                LEFTJOIN@ModifiedRawData A ON A.[Page IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  15+14, 2))))
                                                AND A.[File IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  19+14, 2))))
                                                AND A.[Link ID]<> B.[Link ID]AND B.[Update]=0LEFTJOIN@ModifiedRawData C ON C.[Page IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  27+14, 2))))
                                                AND C.[File IDS]=CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING(B.[RowLog Contents 0],
                                                                  31+14, 2))))
                                                AND C.[Link ID]<> B.[Link ID]AND B.[Update]=0WHERE   ( A.[RowLog Contents 0]ISNOTNULLOR C.[RowLog Contents 0]ISNOTNULL
                )
     
        UPDATE@ModifiedRawDataSET[RowLog Contents 0]= ( CASEWHEN[RowLog Len]>=8000THENSUBSTRING([RowLog Contents 0],
                                                            15, [RowLog Len])
                                             WHEN[RowLog Len]<8000THENSUBSTRING([RowLog Contents 0],
                                                            15+6,
                                                            CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([RowLog Contents 0],
                                                                  15, 6)))))
                                        END )
        FROM@ModifiedRawDataWHERE[LINK ID]=0UPDATE@ColumnNameAndDataSET[hex_Value]=[RowLog Contents 0]--,A.[Update]=A.[Update]+1FROM@ColumnNameAndData A
                INNERJOIN@ModifiedRawData B ONCONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
                                                                  17, 4)))) =[PAGE IDS]ANDCONVERT(INT, SUBSTRING([hex_value],
                                                                  9, 2)) = B.[Link ID]WHERE[System_Type_Id]IN ( 99, 167, 175, 231, 239, 241, 165, 98 )
                AND[Link ID]<>0UPDATE@ColumnNameAndDataSET[hex_Value]= ( CASEWHEN B.[RowLog Contents 0]ISNOTNULLAND C.[RowLog Contents 0]ISNOTNULLTHEN B.[RowLog Contents 0]+ C.[RowLog Contents 0]WHEN B.[RowLog Contents 0]ISNULLAND C.[RowLog Contents 0]ISNOTNULLTHEN C.[RowLog Contents 0]WHEN B.[RowLog Contents 0]ISNOTNULLAND C.[RowLog Contents 0]ISNULLTHEN B.[RowLog Contents 0]END )
        --,A.[Update]=A.[Update]+1FROM@ColumnNameAndData A
                LEFTJOIN@ModifiedRawData B ONCONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
                                                                  5, 4)))) = B.[PAGE IDS]AND B.[Link ID]=0LEFTJOIN@ModifiedRawData C ONCONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
                                                                  17, 4)))) = C.[PAGE IDS]AND C.[Link ID]=0WHERE[System_Type_Id]IN ( 99, 167, 175, 231, 239, 241, 165, 98 )
                AND ( B.[RowLog Contents 0]ISNOTNULLOR C.[RowLog Contents 0]ISNOTNULL
                    )
     
        UPDATE@ColumnNameAndDataSET[hex_Value]=[RowLog Contents 0]--,A.[Update]=A.[Update]+1FROM@ColumnNameAndData A
                INNERJOIN@ModifiedRawData B ONCONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
                                                                  9, 4)))) =[PAGE IDS]ANDCONVERT(INT, SUBSTRING([hex_value],
                                                                  3, 2)) =[Link ID]WHERE[System_Type_Id]IN ( 35, 34, 99 )
                AND[Link ID]<>0UPDATE@ColumnNameAndDataSET[hex_Value]=[RowLog Contents 0]--,A.[Update]=A.[Update]+10FROM@ColumnNameAndData A
                INNERJOIN@ModifiedRawData B ONCONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
                                                                  9, 4)))) =[PAGE IDS]WHERE[System_Type_Id]IN ( 35, 34, 99 )
                AND[Link ID]=0UPDATE@ColumnNameAndDataSET[hex_Value]=[RowLog Contents 0]--,A.[Update]=A.[Update]+1FROM@ColumnNameAndData A
                INNERJOIN@ModifiedRawData B ONCONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],
                                                                  15, 4)))) =[PAGE IDS]WHERE[System_Type_Id]IN ( 35, 34, 99 )
                AND[Link ID]=0UPDATE@ColumnNameAndDataSET[hex_value]=0xFFFE+SUBSTRING([hex_value], 9, LEN([hex_value]))
        --,[Update]=[Update]+1WHERE[system_type_id]=241CREATETABLE[#temp_Data]
            (
              [FieldName]VARCHAR(MAX) ,
              [FieldValue]NVARCHAR(MAX) ,
              [Rowlogcontents]VARBINARY(8000) ,
              [Row ID]INT
            )
     
        INSERTINTO #temp_Data
                SELECT  NAME ,
                        CASEWHEN system_type_id IN ( 231, 239 )
                             THENLTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value)))  --NVARCHAR ,NCHARWHEN system_type_id IN ( 167, 175 )
                             THENLTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value)))  --VARCHAR,CHARWHEN system_type_id IN ( 35 )
                             THENLTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value))) --TextWHEN system_type_id IN ( 99 )
                             THENLTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value))) --nText WHEN system_type_id =48THENCONVERT(VARCHAR(MAX), CONVERT(TINYINT, CONVERT(BINARY(1), REVERSE(hex_Value)))) --TINY INTEGERWHEN system_type_id =52THENCONVERT(VARCHAR(MAX), CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(hex_Value)))) --SMALL INTEGERWHEN system_type_id =56THENCONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(hex_Value)))) -- INTEGERWHEN system_type_id =127THENCONVERT(VARCHAR(MAX), CONVERT(BIGINT, CONVERT(BINARY(8), REVERSE(hex_Value))))-- BIG INTEGERWHEN system_type_id =61THENCONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 100) --DATETIMEWHEN system_type_id =58THENCONVERT(VARCHAR(MAX), CONVERT(SMALLDATETIME, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 100) --SMALL DATETIMEWHEN system_type_id =108THENCONVERT(VARCHAR(MAX), CONVERT(NUMERIC(38, 20), CONVERT(VARBINARY, CONVERT(VARBINARY(1), xprec)
                                  +CONVERT(VARBINARY(1), xscale))
                                  +CONVERT(VARBINARY(1), 0) + hex_Value)) --- NUMERICWHEN system_type_id =106THENCONVERT(VARCHAR(MAX), CONVERT(DECIMAL(38, 20), CONVERT(VARBINARY, CONVERT(VARBINARY(1), xprec)
                                  +CONVERT(VARBINARY(1), xscale))
                                  +CONVERT(VARBINARY(1), 0) + hex_Value)) --- DECIMALWHEN system_type_id IN ( 60, 122 )
                             THENCONVERT(VARCHAR(MAX), CONVERT(MONEY, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 2) --MONEY,SMALLMONEYWHEN system_type_id =104THENCONVERT(VARCHAR(MAX), CONVERT (BIT, CONVERT(BINARY(1), hex_Value)
                                  %2))  -- BITWHEN system_type_id =62THENRTRIM(LTRIM(STR(CONVERT(FLOAT, SIGN(CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) ASBIGINT))
                                                  * ( 1.0+ ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) ASBIGINT)
                                                          &0x000FFFFFFFFFFFFF )
                                                      *POWER(CAST(2ASFLOAT),
                                                              -52) )
                                                  *POWER(CAST(2ASFLOAT),
                                                          ( ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) ASBIGINT)
                                                              &0x7ff0000000000000 )
                                                            /EXP(52*LOG(2))
                                                            -1023 ))), 53,
                                                  LEN(hex_Value)))) --- FLOATWHEN system_type_id =59THENLEFT(LTRIM(STR(CAST(SIGN(CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) ASBIGINT))
                                                 * ( 1.0+ ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) ASBIGINT)
                                                         &0x007FFFFF )
                                                     *POWER(CAST(2ASREAL), -23) )
                                                 *POWER(CAST(2ASREAL),
                                                         ( ( ( CAST(CONVERT(VARBINARY(8000), REVERSE(hex_Value)) ASINT) )
                                                             &0x7f800000 )
                                                           /EXP(23*LOG(2))
                                                           -127 )) ASREAL), 23,
                                                 23)), 8) --RealWHEN system_type_id IN ( 165, 173 )
                             THEN ( CASEWHENCHARINDEX(0x,
                                                        CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'VARBINARY(8000)')) =0THEN'0x'ELSE''END ) +CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'varchar(max)') -- BINARY,VARBINARYWHEN system_type_id =34THEN ( CASEWHENCHARINDEX(0x,
                                                        CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'VARBINARY(8000)')) =0THEN'0x'ELSE''END ) +CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'varchar(max)')  --IMAGEWHEN system_type_id =36THENCONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, hex_Value)) --UNIQUEIDENTIFIERWHEN system_type_id =231THENCONVERT(VARCHAR(MAX), CONVERT(SYSNAME, hex_Value)) --SYSNAMEWHEN system_type_id =241THENCONVERT(VARCHAR(MAX), CONVERT(XML, hex_Value)) --XMLWHEN system_type_id =189THEN ( CASEWHENCHARINDEX(0x,
                                                        CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'VARBINARY(8000)')) =0THEN'0x'ELSE''END ) +CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'varchar(max)') --TIMESTAMPWHEN system_type_id =98THEN ( CASEWHENCONVERT(INT, SUBSTRING(hex_Value, 1,
                                                                  1)) =56THENCONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(SUBSTRING(hex_Value,
                                                                  3,
                                                                  LEN(hex_Value))))))  -- INTEGERWHENCONVERT(INT, SUBSTRING(hex_Value, 1,
                                                                  1)) =108THENCONVERT(VARCHAR(MAX), CONVERT(NUMERIC(38,
                                                                  20), CONVERT(VARBINARY(1), SUBSTRING(hex_Value,
                                                                  3, 1))
                                              +CONVERT(VARBINARY(1), SUBSTRING(hex_Value,
                                                                  4, 1))
                                              +CONVERT(VARBINARY(1), 0)
                                              +SUBSTRING(hex_Value, 5,
                                                          LEN(hex_Value)))) --- NUMERICWHENCONVERT(INT, SUBSTRING(hex_Value, 1,
                                                                  1)) =167THENLTRIM(RTRIM(CONVERT(VARCHAR(MAX), SUBSTRING(hex_Value,
                                                                  9,
                                                                  LEN(hex_Value))))) --VARCHAR,CHARWHENCONVERT(INT, SUBSTRING(hex_Value, 1,
                                                                  1)) =36THENCONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, SUBSTRING(( hex_Value ),
                                                                  3, 20))) --UNIQUEIDENTIFIERWHENCONVERT(INT, SUBSTRING(hex_Value, 1,
                                                                  1)) =61THENCONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(8000), REVERSE(SUBSTRING(hex_Value,
                                                                  3,
                                                                  LEN(hex_Value))))), 100) --DATETIMEWHENCONVERT(INT, SUBSTRING(hex_Value, 1,
                                                                  1)) =165THEN'0x'+SUBSTRING(( CASEWHENCHARINDEX(0x,
                                                                  CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'VARBINARY(8000)')) =0THEN'0x'ELSE''END )
                                                          +CAST(''AS XML).value('xs:hexBinary(sql:column("hex_Value"))',
                                                                  'varchar(max)'),
                                                          11, LEN(hex_Value)) -- BINARY,VARBINARYEND )
                        ENDAS FieldValue ,
                        [Rowlogcontents] ,
                        [Row ID]FROM@ColumnNameAndDataORDERBY nullbit
     
    --Create the column name in the same order to do pivot table.DECLARE@FieldNameVARCHAR(MAX)
        SET@FieldName=STUFF(( SELECT','+CAST(QUOTENAME([Name]) ASVARCHAR(MAX))
                                 FROM   syscolumns
                                 WHERE  id =OBJECT_ID(''+@SchemaName_n_TableName+'')
                               FOR
                                 XML PATH('')
                               ), 1, 1, '')
     
    --Finally did pivot table and get the data back in the same format.SET@sql='SELECT '+@FieldName+' FROM #temp_Data PIVOT (Min([FieldValue]) FOR FieldName IN ('+@FieldName+')) AS pvt'EXEC sp_executesql @sqlGO

    恢复你的数据

    --恢复数据,不加时间段条件  参数:数据库名,表名
    --EXAMPLE #1 : FOR ALL DELETED RECORDSEXEC Recover_Deleted_Data_Proc 'test','dbo.aa'GO--恢复数据,加时间段条件
    --EXAMPLE #2 : FOR ANY SPECIFIC DATE RANGEEXEC Recover_Deleted_Data_Proc 'test','dbo.aa','2014-04-23','2014-04-23'

    执行了下面的存储过程之后你会发现会显示出刚才删除的数据

    EXEC Recover_Deleted_Data_Proc 'test','dbo.aa'GO


    解释

    究竟他是如何工作的?让我们来一步一步来,这个过程涉及到7个步骤:

    步骤1:

    我们需要获得SQLSERVER删除的数据记录.使用标准SQLSERVER函数fn_dblog,我们能够容易的获得事务日志记录(包括

    已删的数据。不过,我们只需要事务日志中选中的被删数据,所以我们的过滤条件需要包含3个字段 Context, Operation & AllocUnitName)

    We need to get the deleted records from sql server. By using the standard SQL Server function fn_blog, we can easily get all transaction log (Including deleted data. But, we need only the selected deleted records from the transaction log. So we included three filters (Context, Operation , AllocUnitName).

    • Context (‘LCX_MARK_AS_GHOST’and ‘LCX_HEAP’)
    • Operation (‘LOP_DELETE_ROWS’)
    • AllocUnitName(‘dbo.aa’) –- Schema + table Name

    Context可以说明是堆表还是聚集表

    Operation:删除操作

    AllocUnitName:分配单元名称,表名

    下面是一个代码片段

    SELECT[RowLog Contents 0]FROM    sys.fn_dblog(NULL, NULL)
    WHERE   AllocUnitName ='dbo.aa'AND Context IN ( 'LCX_MARK_AS_GHOST', 'LCX_HEAP' )
            AND Operation IN ( 'LOP_DELETE_ROWS' )

    这个查询会返回不同列的信息,但是我们只需要选择[RowLog Contents 0]列,去获得被删除的数据的内容

    RowLog content 0列的内容类似于这样

    “0x300018000100000000000000006B0000564920205900000

    00500E001002800426F62206A65727279″

    步骤2:

    现在,我们已经删除了数据,这些数据以hex码的形式放在事务日志里,这些hex码是有规律的,我们根据这些规律可以很容易恢复这些数据。

    不过在恢复这些数据之前,我们需要理解这些格式。这些格式在KalenDelaney’s SQL Internal’s book.的书里面有讲解

    • 1 Byte : Status Bit A
    • 1 Byte : Status Bit B
    • 2 Bytes : Fixed length size
    • n Bytes : Fixed length data
    • 2 Bytes : Total Number of Columns
    • n Bytes : NULL Bitmap (1 bit for each column as 1 indicates that the column is null and 0 indicate that the column is not null)
    • 2 Bytes : Number of variable-length columns
    • n Bytes : Column offset array (2x variable length column)
    • n Bytes : Data for variable length columns

    所以, hex码的“RowLog content 0″列的内容就等价于

    “Status Bit A +Status Bit B +Fixed length size +Fixed length data +Total Number of Columns +NULL Bitmap +Number of variable-length columns +NULL Bitmap+Number of variable-length columns +Column offset array +Data for variable length columns.”

    更详细的可以参考:SQL Server2008存储结构之堆表、行溢出

    关于数据行的结构我们还可以采用稍微宏观一些的视角来查看。

    4
     

    步骤3:

    现在,我们需要解剖RowLog Content o列的内容(我们删除的数据的Hex码),利用上面的数据行的结构

    • [Fixed Length Data] = Substring (RowLog content 0, Status Bit A+Status Bit B + 1,2 bytes)
    • [Total No of Columns]= Substring (RowLog content 0, [Fixed Length Data] + 1,2 bytes)
    • [Null Bitmap length] = Ceiling ([Total No of Columns]/8.0)
    • [Null Bytes]= Substring (RowLog content 0, Status Bit A+ Status Bit B +[Fixed Length Data] +1, [Null Bitmap length] )
    • Total no of variable columns = Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 )
    • Column Offset Array= Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 , Total no of variable columns*2 )
    • Variable Column Start = Status Bit A+ Status Bit B + [Fixed Length Data] + [Null Bitmap length] + 2+( Total no of variable columns*2)

     

    步骤4:

    现在我们已经将hex码切开了(0x300008000100000002000001001300604F7D59),所以,我们能找到删除的行的某列的数据是否为null值

    根据NULL位图。为了完成将NULL Bytes的hex码转换为二进制格式(正如之前讨论的,1表示行中对应的那一列为null,而0则表示对应的列有实际的数据)

    如果还不是明白的童鞋可以看一下我写的这篇文章:《SQLSERVER中NULL位图的作用

     

    步骤5:

    现在,我们已经做了初步的数据分割 (Step-3) 和null值判断(Step-4) 。然后我们需要使用代码片段去获得列数据,例如:列名,列大小,精度,范围

    和最重要的叶子的null位(确保列数据是固定长度的(<=-1表示可变长度)或者固定长度的(>=1))

    使用下面的SQL语句

    SELECT*FROM    sys.allocation_units allocunits
            INNERJOIN sys.partitions partitions ON ( allocunits.type IN ( 1, 3 )
                                                      AND partitions.hobt_id = allocunits.container_id
                                                    )
                                                    OR ( allocunits.type =2AND partitions.partition_id = allocunits.container_id
                                                       )
            INNERJOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_id
            LEFTOUTERJOIN syscolumns ON syscolumns.id = partitions.object_idAND syscolumns.colid = cols.partition_column_id

    与(Step-1,2,3,4) 获得的数据表做join连接,根据allocunits.[Allocation_Unit_Id]。

    现在我们知道表和表中的数据信息,那么我们需要利用这些数据去将 [RowLog Contents 0] 列里的hex码的数据插入到表中的相应列

    现在我们需要关心每一列的数据究竟是固定长度的还是可变长度的

    步骤6:

    我们收集了每列的hex格式的数据。现在我们需要利用[System_type_id]去转换这些数据回去正确的数据类型

    每一种数据类型都有不同的数据类型转换机制。

    --NVARCHAR ,NCHARWHEN system_type_id IN (231, 239) THENLTRIM(RTRIM(CONVERT(NVARCHAR(max),hex_Value)))
     
    --VARCHAR,CHARWHEN system_type_id IN (167,175) THENLTRIM(RTRIM(CONVERT(VARCHAR(max),REPLACE(hex_Value, 0x00, 0x20))))
     
    --TINY INTEGERWHEN system_type_id =48THENCONVERT(VARCHAR(MAX), CONVERT(TINYINT, CONVERT(BINARY(1), REVERSE (hex_Value))))
     
    --SMALL INTEGERWHEN system_type_id =52THENCONVERT(VARCHAR(MAX), CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE (hex_Value))))
     
    -- INTEGERWHEN system_type_id =56THENCONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(hex_Value))))
     
    -- BIG INTEGERWHEN system_type_id =127THENCONVERT(VARCHAR(MAX), CONVERT(BIGINT, CONVERT(BINARY(8), REVERSE(hex_Value))))
     
    --DATETIMEWHEN system_type_id =61ThenCONVERT(VARCHAR(Max),CONVERT(DATETIME,Convert(VARBINARY(max),REVERSE (hex_Value))),100)
     
    --SMALL DATETIMEWHEN system_type_id =58ThenCONVERT(VARCHAR(Max),CONVERT(SMALLDATETIME,CONVERT(VARBINARY(MAX),REVERSE(hex_Value))),100) --SMALL DATETIME--- NUMERICWHEN system_type_id =108THENCONVERT(VARCHAR(MAX), CAST(CONVERT(NUMERIC(18,14), CONVERT(VARBINARY,CONVERT(VARBINARY,xprec)+CONVERT(VARBINARY,xscale))+CONVERT(VARBINARY(1),0) + hex_Value) asFLOAT))
     
    --MONEY,SMALLMONEYWHEN system_type_id In(60,122) THENCONVERT(VARCHAR(MAX),Convert(MONEY,Convert(VARBINARY(MAX),Reverse(hex_Value))),2)
     
    --- DECIMALWHEN system_type_id =106THENCONVERT(VARCHAR(MAX), CAST(CONVERT(Decimal(38,34), Convert(VARBINARY,Convert(VARBINARY,xprec)+CONVERT(VARBINARY,xscale))+CONVERT(VARBINARY(1),0) + hex_Value) asFLOAT))
     
    -- BITWHEN system_type_id =104THENCONVERT(VARCHAR(MAX),CONVERT (BIT,CONVERT(BINARY(1), hex_Value)%2))
     
    --- FLOATWHEN system_type_id =62THENRTRIM(LTRIM(Str(Convert(FLOAT,SIGN(CAST(Convert(VARBINARY(max),Reverse(hex_Value)) ASBIGINT)) * (1.0+ (CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) ASBIGINT) &0x000FFFFFFFFFFFFF) *POWER(CAST(2ASFLOAT), -52)) *POWER(CAST(2ASFLOAT),((CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) ASBIGINT) &0x7ff0000000000000) /EXP(52*LOG(2))-1023))),53,LEN(hex_Value))))
     
    --REALWhen  system_type_id =59THENLeft(LTRIM(STR(Cast(SIGN(CAST(Convert(VARBINARY(max),Reverse(hex_Value)) ASBIGINT))* (1.0+ (CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) ASBIGINT) &0x007FFFFF) *POWER(CAST(2ASReal), -23)) *POWER(CAST(2ASReal),(((CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) ASINT) )&0x7f800000)/EXP(23*LOG(2))-127))ASREAL),23,23)),8)
     
    --BINARY,VARBINARYWHEN system_type_id In (165,173) THEN (CASEWHENCharindex(0x,cast(''AS XML).value('xs:hexBinary(sql:column("hex_value"))', 'varbinary(max)')) =0THEN'0x'ELSE''END) +cast(''AS XML).value('xs:hexBinary(sql:column("hex_value"))', 'varchar(max)') 
     
    --UNIQUEIDENTIFIER WHEN system_type_id =36THENCONVERT(VARCHAR(MAX),CONVERT(UNIQUEIDENTIFIER,hex_Value)) 

    步骤7:

    最终我们做一个数据透视表,你会看到最后的结果:被删的数据回来了!

    注意:这些数据只是展示出来并没有自动插入回表中,你需要将这些数据重新插入回去表中!


    我的测试

    经过测试,作者写的这个存储过程还是有些问题

    如果你创建的测试表的数据类型有xml或者是一些text数据类型的字段会有报错

    Msg 537, Level16, State 3, Procedure Recover_Deleted_Data_Proc, Line 525
    Invalid length parameter passed to the LEFTorSUBSTRINGfunction.
    
    Msg 9420, Level16, State 1, Procedure Recover_Deleted_Data_Proc, Line 651
    XML parsing: line 1, character2, illegal xml character

    但是一般的数据类型则不会,例如nvarchar这些

    还有不要在存储过程的最后加

    --Recover the deleted data without date rangeEXEC Recover_Deleted_Data_Proc 'test','dbo.Test_Table'GO--Recover the deleted data it with date rangeEXEC Recover_Deleted_Data_Proc 'test','dbo.Test_Table','2012-06-01','2012-06-30'

    否则会报错

    消息 50000,级别 16,状态 1,过程 Recover_Deleted_Data_Proc,第 290 行
    There is no data in the logas per the search criteria

    总结

    实际上这个存储过程还是挺有研究意义的,对于想做一个跟Log Explorer for SQL Server软件功能差不多的软件出来

    还是有可能的,跟着作者的思路,一步一步实现

    苦于最近太忙,先分享出来,以后再研究这个存储过程了~

    如果有来生,一个人去远行,看不同的风景,感受生命的活力。。。
  • 相关阅读:
    图像处理之基础---卷积及其快速算法的C++实现
    嵌入式c语言笔试
    逻辑题
    多媒体开发之---h264 图像参数级语义
    多媒体开发之---h264 取流解码实现
    多媒体开发之---live555 分析客户端
    多媒体开发之---如何确定slice_header slice_type 的位置
    图像处理之基础---很好的一个开源文档库
    多媒体开发之---h264 高度和宽度获取
    Flutter实战视频-移动电商-65.会员中心_订单区域UI布局
  • 原文地址:https://www.cnblogs.com/Frank99/p/5951222.html
Copyright © 2011-2022 走看看