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软件功能差不多的软件出来

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

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

    如果有来生,一个人去远行,看不同的风景,感受生命的活力。。。
  • 相关阅读:
    Java实现 蓝桥杯 算法训练 Number Challenge(暴力)
    Java实现 蓝桥杯 算法训练 Number Challenge(暴力)
    Java实现 蓝桥杯 算法训练 Number Challenge(暴力)
    Java实现 蓝桥杯 算法训练 Rotatable Number(暴力)
    Java实现 蓝桥杯 算法训练 Rotatable Number(暴力)
    Java实现 蓝桥杯 算法训练 Rotatable Number(暴力)
    Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)
    Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)
    Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)
    Python位运算符
  • 原文地址:https://www.cnblogs.com/Frank99/p/5951222.html
Copyright © 2011-2022 走看看