[MSSQL] Delete 명령어로 지워버린 데이터 복구하기

[MSSQL] Delete 명령어로 지워버린 데이터 복구하기 


http://blog.naver.com/PostView.nhn?blogId=platinasnow&logNo=220172506297​



0. 들어가기 전에


 DB에서 데이터를 주물럭 거리다가 DELETE명령어를 잘 못 날려서 데이터를 싹 날려버리신 경험 한번 쯤은 있으실겁니다. MSSQL은 기본적으로 AUTO COMMIT 이기 때문에 DELETE를 해버리면 ROLLBACK 할 수가 없습니다. 백업한 파일도 없고 정말 중요한 데이터라면 식은 땀이 삐질삐질 나기 시작하는데요. MSSQL에서는 DELETE된 파일도 LOG에 쌓아둡니다. 검색하다가 찾아낸 방법을 공유해봅니다.

 

이 방법은 MSSQL 2005 이상 버전에서만 유효합니다.

자세한 설명은 아래의 포스팅에 잘 나와있습니다. 

출처 : 


 

1. 프로시저 생성

 

​복구할 프로시저를 생성합니다. 아래의 쿼리를 실행하시면 됩니다. 

 

GO

Create PROCEDURE Recover_Deleted_Data_Proc

@Database_Name NVARCHAR(MAX),

@SchemaName_n_TableName NVARCHAR(Max),

@Date_From DATETIME='1900/01/01',

@Date_To DATETIME ='9999/12/31'

AS

 

DECLARE @RowLogContents VARBINARY(8000)

DECLARE @TransactionID NVARCHAR(Max)

DECLARE @AllocUnitID BIGINT

DECLARE @AllocUnitName NVARCHAR(Max)

DECLARE @SQL NVARCHAR(Max)

DECLARE @Compatibility_Level INT

 

 

SELECT @Compatibility_Level=dtb.compatibility_level

FROM

master.sys.databases AS dtb WHERE dtb.name=@Database_Name

/* 

IF ISNULL(@Compatibility_Level,0)<=80

BEGIN

    RAISERROR('The compatibility level should be equal to or greater SQL SERVER 2005 (90)',16,1)

    RETURN

END

 */

IF (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE [TABLE_SCHEMA]+'.'+[TABLE_NAME]=@SchemaName_n_TableName)=0

BEGIN

    RAISERROR('Could not found the table in the defined database',16,1)

    RETURN

END

 

DECLARE @bitTable TABLE

(

  [ID] INT,

  [Bitvalue] INT

)

--Create table to set the bit position of one byte.

 

INSERT INTO @bitTable

SELECT 0,2 UNION ALL

SELECT 1,2 UNION ALL

SELECT 2,4 UNION ALL

SELECT 3,8 UNION ALL

SELECT 4,16 UNION ALL

SELECT 5,32 UNION ALL

SELECT 6,64 UNION ALL

SELECT 7,128

 

--Create table to collect the row data.

DECLARE @DeletedRecords TABLE

(

    [Row ID]            INT IDENTITY(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 )

,(CASE WHEN SUBSTRING([RowLog Contents 0], 1, 1) In (0x10,0x30,0x70) THEN

CONVERT(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))))  ELSE null  END) AS [TotalNoofVarCols] 

 

--[ColumnOffsetArray]= Substring (RowLog content 0, Status Bit A+ Status Bit B + [Fixed Length Data] +1, [Null Bitmap length] + 2 , [TotalNoofVarCols]*2 )

,(CASE WHEN SUBSTRING([RowLog Contents 0], 1, 1) In (0x10,0x30,0x70) THEN

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

, (CASE WHEN SUBSTRING([RowLog Contents 0], 1, 1) In (0x10,0x30,0x70) THEN

CONVERT(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))))  ELSE null  END)

* 2)  ELSE null  END) AS [ColumnOffsetArray] 

 

--  Variable column Start = Status Bit A+ Status Bit B + [Fixed Length Data] + [Null Bitmap length] + 2+([TotalNoofVarCols]*2)

,CASE WHEN SUBSTRING([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)) 

 

+ ((CASE WHEN SUBSTRING([RowLog Contents 0], 1, 1) In (0x10,0x30,0x70) THEN

CONVERT(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))))  ELSE null  END) * 2)) 

 

ELSE null End AS [VarColumnStart]

,[Slot ID]

FROM sys.fn_dblog(NULL, NULL)

WHERE

AllocUnitId IN

(SELECT [Allocation_unit_id] FROM sys.allocation_units allocunits

INNER JOIN sys.partitions partitions ON (allocunits.type IN (1, 3)  

AND partitions.hobt_id = allocunits.container_id) OR (allocunits.type = 2 

AND partitions.partition_id = allocunits.container_id)  

WHERE object_id=object_ID('' + @SchemaName_n_TableName + ''))

 

AND Context IN ('LCX_MARK_AS_GHOST', 'LCX_HEAP') AND Operation in ('LOP_DELETE_ROWS') 

And SUBSTRING([RowLog Contents 0], 1, 1)In (0x10,0x30,0x70)

 

/*Use this subquery to filter the date*/

AND [TRANSACTION ID] IN (SELECT DISTINCT [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')

And  CONVERT(NVARCHAR(11),[Begin Time]) BETWEEN @Date_From AND @Date_To)),

 

--Use this technique to repeate the row till the no of bytes of the row.

N1 (n) AS (SELECT 1 UNION ALL SELECT 1),

N2 (n) AS (SELECT 1 FROM N1 AS X, N1 AS Y),

N3 (n) AS (SELECT 1 FROM N2 AS X, N2 AS Y),

N4 (n) AS (SELECT ROW_NUMBER() OVER(ORDER BY X.n)

           FROM N3 AS X, N3 AS Y)

 

 

 

INSERT INTO @DeletedRecords

SELECT  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 ',' +

        (CASE WHEN [ID]=0 THEN CONVERT(NVARCHAR(1),(SUBSTRING(NullBytes, n, 1) % 2))  ELSE CONVERT(NVARCHAR(1),((SUBSTRING(NullBytes, n, 1) / [Bitvalue]) % 2)) END) --as [nullBitMap]

         

FROM

N4 AS Nums

Join RowData AS C ON n<=NullBitMapLength

Cross Join @bitTable WHERE C.[RowLogContents]=D.[RowLogContents] ORDER BY [RowLogContents],n ASC FOR XML PATH('')),1,1,''),',',''))

FROM RowData D

 

IF (SELECT COUNT(*) FROM @DeletedRecords)=0

BEGIN

    RAISERROR('There is no data in the log as per the search criteria',16,1)

    RETURN

END

 

DECLARE @ColumnNameAndData TABLE

(

 [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

--)

INSERT INTO @ColumnNameAndData

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,

(CASE WHEN leaf_offset<1 and SUBSTRING([nullBitMap], cols.leaf_null_bit, 1)=0 

THEN

(Case When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000

THEN

CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) - POWER(2, 15)

ELSE

CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2))))

END)

END)  AS [Column value Size],

 

(CASE WHEN leaf_offset<1 and SUBSTRING([nullBitMap], cols.leaf_null_bit, 1)=0  THEN

(Case

 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])<30000

THEN  (Case When [System_type_id]In (35,34,99) Then 16 else 24  end)

 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])>30000

THEN  (Case When [System_type_id]In (35,34,99) Then 16 else 24  end) --24 

 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) <30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])<30000

THEN (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]))

 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) <30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])>30000

 

THEN POWER(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]

 

,(CASE WHEN SUBSTRING([nullBitMap], cols.leaf_null_bit, 1)=1 THEN  NULL ELSE

 SUBSTRING

 (

 Rowlogcontents, 

 (

 

(Case When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000

THEN

CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) - POWER(2, 15)

ELSE

CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2))))

END)

 

 - 

(Case When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])<30000

 

THEN  (Case When [System_type_id]In (35,34,99) Then 16 else 24  end) --24 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])>30000

 

THEN  (Case When [System_type_id]In (35,34,99) Then 16 else 24  end) --24 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) <30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])<30000

 

THEN 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])

 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) <30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])>30000

 

THEN POWER(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,

(Case When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])<30000

 

THEN  (Case When [System_type_id] In (35,34,99) Then 16 else 24  end) --24 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) >30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])>30000

 

THEN  (Case When [System_type_id] In (35,34,99) Then 16 else 24  end) --24 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) <30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])<30000

 

THEN ABS(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]))

 

When CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * leaf_offset*-1) - 1, 2)))) <30000 And

ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE (SUBSTRING ([ColumnOffsetArray], (2 * ((leaf_offset*-1) - 1)) - 1, 2)))), 0), [varColumnStart])>30000

 

THEN POWER(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]

,0

FROM @DeletedRecords A

Inner Join sys.allocation_units allocunits On A.[AllocUnitId]=allocunits.[Allocation_Unit_Id]

INNER JOIN sys.partitions partitions ON (allocunits.type IN (1, 3)

AND partitions.hobt_id = allocunits.container_id) OR (allocunits.type = 2 AND partitions.partition_id = allocunits.container_id)

INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_id

LEFT OUTER JOIN syscolumns ON syscolumns.id = partitions.object_id AND syscolumns.colid = cols.partition_column_id

WHERE leaf_offset<0

UNION

/*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,

(SELECT TOP 1 ISNULL(SUM(CASE WHEN C.leaf_offset >1 THEN max_length ELSE 0 END),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 AS [Column value Size],

syscolumns.length AS [Column Length]

 

,CASE WHEN SUBSTRING([nullBitMap], cols.leaf_null_bit, 1)=1 THEN NULL ELSE

SUBSTRING

(

Rowlogcontents,(SELECT TOP 1 ISNULL(SUM(CASE WHEN C.leaf_offset >1 And C.leaf_bit_position=0 THEN max_length ELSE 0 END),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) END AS hex_Value

,[Slot ID]

,0

FROM @DeletedRecords A

Inner Join sys.allocation_units allocunits ON A.[AllocUnitId]=allocunits.[Allocation_Unit_Id]

INNER JOIN sys.partitions partitions ON (allocunits.type IN (1, 3)

AND partitions.hobt_id = allocunits.container_id) OR (allocunits.type = 2 AND partitions.partition_id = allocunits.container_id)

INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_id

LEFT OUTER JOIN syscolumns ON syscolumns.id = partitions.object_id AND syscolumns.colid = cols.partition_column_id

WHERE leaf_offset>0

Order By nullbit

 

Declare @BitColumnByte as int

Select @BitColumnByte=CONVERT(INT, ceiling( Count(*)/8.0)) from @ColumnNameAndData Where [System_Type_id]=104

 

;With N1 (n) AS (SELECT 1 UNION ALL SELECT 1),

N2 (n) AS (SELECT 1 FROM N1 AS X, N1 AS Y),

N3 (n) AS (SELECT 1 FROM N2 AS X, N2 AS Y),

N4 (n) AS (SELECT ROW_NUMBER() OVER(ORDER BY X.n)

           FROM N3 AS X, N3 AS Y),

CTE As(

Select RowLogContents,[nullbit]

        ,[BitMap]=Convert(varbinary(1),Convert(int,Substring((REPLACE(STUFF((SELECT ',' +

        (CASE WHEN [ID]=0 THEN CONVERT(NVARCHAR(1),(SUBSTRING(hex_Value, n, 1) % 2))  ELSE CONVERT(NVARCHAR(1),((SUBSTRING(hex_Value, n, 1) / [Bitvalue]) % 2)) END) --as [nullBitMap]

 

from N4 AS Nums

Join @ColumnNameAndData AS C ON n<=@BitColumnByte And [System_Type_id]=104 And bitpos=0

Cross Join @bitTable WHERE C.[RowLogContents]=D.[RowLogContents] ORDER BY [RowLogContents],n ASC FOR XML PATH('')),1,1,''),',','')),bitpos+1,1)))

FROM @ColumnNameAndData D Where  [System_Type_id]=104)

 

Update A Set [hex_Value]=[BitMap]

from @ColumnNameAndData  A

Inner Join CTE B On A.[RowLogContents]=B.[RowLogContents]

And A.[nullbit]=B.[nullbit]

 

 

/**************Check for BLOB DATA TYPES******************************/

DECLARE @Fileid INT

DECLARE @Pageid INT

DECLARE @Slotid INT

DECLARE @CurrentLSN INT

DECLARE @LinkID INT

DECLARE @Context VARCHAR(50)

DECLARE @ConsolidatedPageID VARCHAR(MAX)

DECLARE @LCX_TEXT_MIX VARBINARY(MAX)

 

declare @temppagedata table

(

[ParentObject] sysname,

[Object] sysname,

[Field] sysname,

[Value] sysname)

 

declare @pagedata table

(

[Page ID] sysname,

[File IDS] int,

[Page IDS] int,

[AllocUnitId] bigint,

[ParentObject] sysname,

[Object] sysname,

[Field] sysname,

[Value] sysname)

 

DECLARE @ModifiedRawData TABLE

(

  [ID] INT IDENTITY(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] INT default (0),

  [Update] INT

)

 

            DECLARE Page_Data_Cursor CURSOR FOR

            /*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*/

            SELECT LTRIM(RTRIM(Replace([Description],'Deallocated',''))) AS [PAGE ID]

            ,[Slot ID],[AllocUnitId],NULL AS [RowLog Contents 0],NULL AS [RowLog Contents 0],Context

            FROM    sys.fn_dblog(NULL, NULL)  

            WHERE   

            AllocUnitId IN

            (SELECT [Allocation_unit_id] FROM sys.allocation_units allocunits

            INNER JOIN sys.partitions partitions ON (allocunits.type IN (1, 3)  

            AND partitions.hobt_id = allocunits.container_id) OR (allocunits.type = 2 

            AND partitions.partition_id = allocunits.container_id)  

            WHERE object_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 (SELECT DISTINCT [TRANSACTION ID] FROM    sys.fn_dblog(NULL, NULL) 

            WHERE Context IN ('LCX_NULL') AND Operation in ('LOP_BEGIN_XACT')  

            AND [Transaction Name]='DELETE'

            AND  CONVERT(NVARCHAR(11),[Begin Time]) BETWEEN @Date_From AND @Date_To)

            GROUP BY [Description],[Slot ID],[AllocUnitId],Context

 

            UNION

 

            SELECT [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

            INNER JOIN sys.partitions partitions ON (allocunits.type IN (1, 3)  

            AND partitions.hobt_id = allocunits.container_id) OR (allocunits.type = 2 

            AND partitions.partition_id = allocunits.container_id)  

            WHERE object_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 (SELECT DISTINCT [TRANSACTION ID] FROM    sys.fn_dblog(NULL, NULL) 

            WHERE Context IN ('LCX_NULL') AND Operation in ('LOP_BEGIN_XACT')  

            And [Transaction Name]='DELETE'

            And  CONVERT(NVARCHAR(11),[Begin Time]) BETWEEN @Date_From AND @Date_To)

                         

            /****************************************/

 

        OPEN Page_Data_Cursor

 

        FETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,@AllocUnitID,@LCX_TEXT_MIX,@LinkID,@Context

 

        WHILE @@FETCH_STATUS = 0

        BEGIN

            DECLARE @hex_pageid AS VARCHAR(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 ID

         

            SET @hex_pageid ='0x'+ SUBSTRING(@ConsolidatedPageID,CHARINDEX(':',@ConsolidatedPageID)+1,Len(@ConsolidatedPageID))  ---Seperate the page ID

            SELECT @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 integer

            FROM (SELECT CASE substring(@hex_pageid, 1, 2) WHEN '0x' THEN 3 ELSE 0 END) AS t(pos) 

             

            IF @Context='LCX_PFS'    

              BEGIN

                        DELETE @temppagedata

                        INSERT INTO @temppagedata EXEC( 'DBCC PAGE(' + @DataBase_Name + ', ' + @fileid + ', ' + @pageid + ', 1) with tableresults,no_infomsgs;'); 

                        INSERT INTO @pagedata SELECT @ConsolidatedPageID,@fileid,@pageid,@AllocUnitID,[ParentObject],[Object],[Field] ,[Value] FROM @temppagedata

              END

            ELSE IF @Context='LCX_TEXT_MIX'

              BEGIN

                        INSERT INTO  @ModifiedRawData SELECT @ConsolidatedPageID,@fileid,@pageid,@Slotid,@AllocUnitID,NULL,0,CONVERT(INT,CONVERT(VARBINARY,REVERSE(SUBSTRING(@LCX_TEXT_MIX,11,2)))),@LCX_TEXT_MIX,@LinkID,0

              END    

            FETCH NEXT FROM Page_Data_Cursor INTO  @ConsolidatedPageID, @Slotid,@AllocUnitID,@LCX_TEXT_MIX,@LinkID,@Context

        END

     

    CLOSE Page_Data_Cursor

    DEALLOCATE Page_Data_Cursor

 

    DECLARE @Newhexstring VARCHAR(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 format

    INSERT INTO @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((

    SELECT

    REPLACE(STUFF((SELECT REPLACE(SUBSTRING([Value],CHARINDEX(':',[Value])+1,CHARINDEX('†',[Value])-CHARINDEX(':',[Value])),'†','')

    FROM @pagedata C  WHERE B.[Page ID]= C.[Page ID] And Substring(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%'  Order By '0x'+ LEFT([Value],CHARINDEX(':',[Value])-1)

    FOR XML PATH('') ),1,1,'') ,' ','')

    ),1,20000) AS [Value]

     

    ,

     Substring((

    SELECT '0x' +REPLACE(STUFF((SELECT REPLACE(SUBSTRING([Value],CHARINDEX(':',[Value])+1,CHARINDEX('†',[Value])-CHARINDEX(':',[Value])),'†','')

    FROM @pagedata C  WHERE B.[Page ID]= C.[Page ID] And Substring(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%'  Order By '0x'+ LEFT([Value],CHARINDEX(':',[Value])-1)

    FOR XML PATH('') ),1,1,'') ,' ','')

    ),7,4) AS [Length]

     

    From @pagedata B

    Where [Object] Like '%Memory Dump%'

    Group By [Page ID],[FILE IDS],[PAGE IDS],[ParentObject],[AllocUnitId]--,[Current LSN]

    Order By [Slot ID]

 

    UPDATE @ModifiedRawData  SET [RowLog Len] = CONVERT(VARBINARY(8000),REVERSE(cast('' AS XML).value('xs:hexBinary(substring(sql:column("[RowLog Length]"),0))', 'varbinary(Max)')))

    FROM @ModifiedRawData Where [LINK ID]=0

 

    UPDATE @ModifiedRawData  SET [RowLog Contents 0] =cast('' AS XML).value('xs:hexBinary(substring(sql:column("[RowLog Contents 0_var]"),0))', 'varbinary(Max)')  

    FROM @ModifiedRawData Where [LINK ID]=0

 

    Update B Set B.[RowLog Contents 0] =

    (CASE WHEN A.[RowLog Contents 0] IS NOT NULL AND C.[RowLog Contents 0] IS NOT NULL THEN  A.[RowLog Contents 0]+C.[RowLog Contents 0] 

        WHEN A.[RowLog Contents 0] IS NULL AND C.[RowLog Contents 0] IS NOT NULL THEN  C.[RowLog Contents 0]

        WHEN A.[RowLog Contents 0] IS NOT NULL AND C.[RowLog Contents 0] IS NULL THEN  A.[RowLog Contents 0]  

        END)

    ,B.[Update]=ISNULL(B.[Update],0)+1

    from @ModifiedRawData B

    LEFT Join @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]

    LEFT Join @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] IS NOT NULL OR C.[RowLog Contents 0] IS NOT NULL)

 

 

    Update B Set B.[RowLog Contents 0] =

    (CASE WHEN A.[RowLog Contents 0] IS NOT NULL AND C.[RowLog Contents 0] IS NOT NULL THEN  A.[RowLog Contents 0]+C.[RowLog Contents 0] 

        WHEN A.[RowLog Contents 0] IS NULL AND C.[RowLog Contents 0] IS NOT NULL THEN  C.[RowLog Contents 0]

        WHEN A.[RowLog Contents 0] IS NOT NULL AND C.[RowLog Contents 0] IS NULL THEN  A.[RowLog Contents 0]  

        END)

    --,B.[Update]=ISNULL(B.[Update],0)+1

    from @ModifiedRawData B

    LEFT Join @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]=0

    LEFT Join @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]=0

    Where  (A.[RowLog Contents 0] IS NOT NULL OR C.[RowLog Contents 0] IS NOT NULL)

 

    UPDATE @ModifiedRawData  SET [RowLog Contents 0] =  

    (Case When [RowLog Len]>=8000 Then

    Substring([RowLog Contents 0] ,15,[RowLog Len]) 

    When [RowLog Len]<8000 Then

    SUBSTRING([RowLog Contents 0],15+6,Convert(int,Convert(varbinary(max),REVERSE(Substring([RowLog Contents 0],15,6)))))

    End)

    FROM @ModifiedRawData Where [LINK ID]=0

 

    UPDATE @ColumnNameAndData SET [hex_Value]=[RowLog Contents 0] 

    --,A.[Update]=A.[Update]+1

    FROM @ColumnNameAndData A

    INNER JOIN @ModifiedRawData B ON

    Convert(int,Convert(Varbinary(Max),Reverse(Substring([hex_value],17,4))))=[PAGE IDS]

    AND  Convert(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] <>0 

 

    UPDATE @ColumnNameAndData SET [hex_Value]=

    (CASE WHEN B.[RowLog Contents 0] IS NOT NULL AND C.[RowLog Contents 0] IS NOT NULL THEN  B.[RowLog Contents 0]+C.[RowLog Contents 0] 

    WHEN B.[RowLog Contents 0] IS NULL AND C.[RowLog Contents 0] IS NOT NULL THEN  C.[RowLog Contents 0]

    WHEN B.[RowLog Contents 0] IS NOT NULL AND C.[RowLog Contents 0] IS NULL THEN  B.[RowLog Contents 0]  

    END)

    --,A.[Update]=A.[Update]+1

    FROM @ColumnNameAndData A

    LEFT JOIN @ModifiedRawData B ON

    Convert(int,Convert(Varbinary(Max),Reverse(Substring([hex_value],5,4))))=B.[PAGE IDS]  And B.[Link ID] =0 

    LEFT JOIN @ModifiedRawData C ON

    Convert(int,Convert(Varbinary(Max),Reverse(Substring([hex_value],17,4))))=C.[PAGE IDS]  And C.[Link ID] =0 

    Where [System_Type_Id] In (99,167,175,231,239,241,165,98)  And (B.[RowLog Contents 0] IS NOT NULL OR C.[RowLog Contents 0] IS NOT NULL)

 

    UPDATE @ColumnNameAndData SET [hex_Value]=[RowLog Contents 0] 

    --,A.[Update]=A.[Update]+1

    FROM @ColumnNameAndData A

    INNER JOIN @ModifiedRawData B ON

    Convert(int,Convert(Varbinary(Max),Reverse(Substring([hex_value],9,4))))=[PAGE IDS]

    And Convert(int,Substring([hex_value],3,2))=[Link ID]

    Where [System_Type_Id] In (35,34,99) And [Link ID] <>0 

     

    UPDATE @ColumnNameAndData SET [hex_Value]=[RowLog Contents 0]

    --,A.[Update]=A.[Update]+10

    FROM @ColumnNameAndData A

    INNER JOIN @ModifiedRawData B ON

    Convert(int,Convert(Varbinary(Max),Reverse(Substring([hex_value],9,4))))=[PAGE IDS]

    Where [System_Type_Id] In (35,34,99) And [Link ID] =0

 

    UPDATE @ColumnNameAndData SET [hex_Value]=[RowLog Contents 0] 

    --,A.[Update]=A.[Update]+1

    FROM @ColumnNameAndData A

    INNER JOIN @ModifiedRawData B ON

    Convert(int,Convert(Varbinary(Max),Reverse(Substring([hex_value],15,4))))=[PAGE IDS]

    Where [System_Type_Id] In (35,34,99) And [Link ID] =0

 

    Update @ColumnNameAndData set [hex_value]= 0xFFFE + Substring([hex_value],9,LEN([hex_value]))

    --,[Update]=[Update]+1

    Where [system_type_id]=241

 

CREATE TABLE [#temp_Data]

(

    [FieldName]  VARCHAR(MAX),

    [FieldValue] NVARCHAR(MAX),

    [Rowlogcontents] VARBINARY(8000),

    [Row ID] int

)

 

INSERT INTO #temp_Data

SELECT NAME,

CASE

 WHEN system_type_id IN (231, 239) THEN  LTRIM(RTRIM(CONVERT(NVARCHAR(max),hex_Value)))  --NVARCHAR ,NCHAR

 WHEN system_type_id IN (167,175) THEN  LTRIM(RTRIM(CONVERT(VARCHAR(max),hex_Value)))  --VARCHAR,CHAR

 WHEN system_type_id IN (35) THEN  LTRIM(RTRIM(CONVERT(VARCHAR(max),hex_Value))) --Text

 WHEN system_type_id IN (99) THEN  LTRIM(RTRIM(CONVERT(NVARCHAR(max),hex_Value))) --nText 

 WHEN system_type_id = 48 THEN CONVERT(VARCHAR(MAX), CONVERT(TINYINT, CONVERT(BINARY(1), REVERSE (hex_Value)))) --TINY INTEGER

 WHEN system_type_id = 52 THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE (hex_Value)))) --SMALL INTEGER

 WHEN system_type_id = 56 THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(hex_Value)))) -- INTEGER

 WHEN system_type_id = 127 THEN CONVERT(VARCHAR(MAX), CONVERT(BIGINT, CONVERT(BINARY(8), REVERSE(hex_Value))))-- BIG INTEGER

 WHEN system_type_id = 61 Then CONVERT(VARCHAR(MAX),CONVERT(DATETIME,CONVERT(VARBINARY(8000),REVERSE (hex_Value))),100) --DATETIME

 WHEN system_type_id =58 Then CONVERT(VARCHAR(MAX),CONVERT(SMALLDATETIME,CONVERT(VARBINARY(8000),REVERSE(hex_Value))),100) --SMALL DATETIME

 WHEN system_type_id = 108 THEN CONVERT(VARCHAR(MAX),CONVERT(NUMERIC(38,20), CONVERT(VARBINARY,CONVERT(VARBINARY(1),xprec)+CONVERT(VARBINARY(1),xscale))+CONVERT(VARBINARY(1),0) + hex_Value)) --- NUMERIC

 WHEN system_type_id =106 THEN CONVERT(VARCHAR(MAX), CONVERT(DECIMAL(38,20), CONVERT(VARBINARY,Convert(VARBINARY(1),xprec)+CONVERT(VARBINARY(1),xscale))+CONVERT(VARBINARY(1),0) + hex_Value)) --- DECIMAL

 WHEN system_type_id In(60,122) THEN CONVERT(VARCHAR(MAX),Convert(MONEY,Convert(VARBINARY(8000),Reverse(hex_Value))),2) --MONEY,SMALLMONEY

 WHEN system_type_id = 104 THEN CONVERT(VARCHAR(MAX),CONVERT (BIT,CONVERT(BINARY(1), hex_Value)%2))  -- BIT

 WHEN system_type_id =62 THEN  RTRIM(LTRIM(STR(CONVERT(FLOAT,SIGN(CAST(CONVERT(VARBINARY(8000),Reverse(hex_Value)) AS BIGINT)) * (1.0 + (CAST(CONVERT(VARBINARY(8000),Reverse(hex_Value)) AS BIGINT) & 0x000FFFFFFFFFFFFF) * POWER(CAST(2 AS FLOAT), -52)) * POWER(CAST(2 AS FLOAT),((CAST(CONVERT(VARBINARY(8000),Reverse(hex_Value)) AS BIGINT) & 0x7ff0000000000000) / EXP(52 * LOG(2))-1023))),53,LEN(hex_Value)))) --- FLOAT

 When system_type_id =59 THEN  Left(LTRIM(STR(CAST(SIGN(CAST(Convert(VARBINARY(8000),REVERSE(hex_Value)) AS BIGINT))* (1.0 + (CAST(CONVERT(VARBINARY(8000),Reverse(hex_Value)) AS BIGINT) & 0x007FFFFF) * POWER(CAST(2 AS Real), -23)) * POWER(CAST(2 AS Real),(((CAST(CONVERT(VARBINARY(8000),Reverse(hex_Value)) AS INT) )& 0x7f800000)/ EXP(23 * LOG(2))-127))AS REAL),23,23)),8) --Real

 WHEN system_type_id In (165,173) THEN (CASE WHEN CHARINDEX(0x,cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'VARBINARY(8000)')) = 0 THEN '0x' ELSE '' END) +cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'varchar(max)') -- BINARY,VARBINARY

 WHEN system_type_id =34 THEN (CASE WHEN CHARINDEX(0x,cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'VARBINARY(8000)')) = 0 THEN '0x' ELSE '' END) +cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'varchar(max)')  --IMAGE

 WHEN system_type_id =36 THEN CONVERT(VARCHAR(MAX),CONVERT(UNIQUEIDENTIFIER,hex_Value)) --UNIQUEIDENTIFIER

 WHEN system_type_id =231 THEN CONVERT(VARCHAR(MAX),CONVERT(sysname,hex_Value)) --SYSNAME

 WHEN system_type_id =241 THEN CONVERT(VARCHAR(MAX),CONVERT(xml,hex_Value)) --XML

 

 WHEN system_type_id =189 THEN (CASE WHEN CHARINDEX(0x,cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'VARBINARY(8000)')) = 0 THEN '0x' ELSE '' END) +cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'varchar(max)') --TIMESTAMP

 WHEN system_type_id=98 THEN (CASE

 WHEN CONVERT(INT,SUBSTRING(hex_Value,1,1))=56 THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(Substring(hex_Value,3,Len(hex_Value))))))  -- INTEGER

 WHEN CONVERT(INT,SUBSTRING(hex_Value,1,1))=108 THEN CONVERT(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)))) --- NUMERIC

 WHEN CONVERT(INT,SUBSTRING(hex_Value,1,1))=167 THEN LTRIM(RTRIM(CONVERT(VARCHAR(max),Substring(hex_Value,9,Len(hex_Value))))) --VARCHAR,CHAR

 WHEN CONVERT(INT,SUBSTRING(hex_Value,1,1))=36 THEN CONVERT(VARCHAR(MAX),CONVERT(UNIQUEIDENTIFIER,Substring((hex_Value),3,20))) --UNIQUEIDENTIFIER

 WHEN CONVERT(INT,SUBSTRING(hex_Value,1,1))=61 THEN CONVERT(VARCHAR(MAX),CONVERT(DATETIME,CONVERT(VARBINARY(8000),REVERSE (Substring(hex_Value,3,LEN(hex_Value)) ))),100) --DATETIME

 WHEN CONVERT(INT,SUBSTRING(hex_Value,1,1))=165 THEN '0x'+ SUBSTRING((CASE WHEN CHARINDEX(0x,cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'VARBINARY(8000)')) = 0 THEN '0x' ELSE '' END) +cast('' AS XML).value('xs:hexBinary(sql:column("hex_Value"))', 'varchar(max)'),11,LEN(hex_Value)) -- BINARY,VARBINARY

 END)

  

END AS FieldValue

,[Rowlogcontents]

,[Row ID]

FROM @ColumnNameAndData ORDER BY nullbit

 

--Create the column name in the same order to do pivot table.

 

DECLARE @FieldName VARCHAR(max)

SET @FieldName = STUFF(

(

    SELECT ',' + CAST(QUOTENAME([Name]) AS VARCHAR(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 @sql

 

 

 

2. 프로시저를 실행합니다.

 

위의 프로시저를 분석하시면 아시겠지만, 2가지 방법을 제공합니다.

아래와 같은 방법으로 실행 하시면 delete했던 데이터들이 그대로 불러져 나옵니다.

-- EXEC Recover_Deleted_Data_Proc '[DB스키마 이름]','[TABLE 이름]'  

EXEC Recover_Deleted_Data_Proc 'master','dbo.dummytable'

 

-- EXEC Recover_Deleted_Data_Proc '[DB스키마 이름]','[TABLE 이름]' ,'[시작일]','[종료일]'

EXEC Recover_Deleted_Data_Proc 'master','dbo.testuser' ,'2014/11/05','2014/11/05'

 

 

 

3. 나온 결과를 excel 등의 형식으로 추출합니다.

 

2번의 결과로 나온 데이터를 추출합니다. 

 

 

4. 추출된 데이터를 데이터 가져오기 등의 방법으로 다시 밀어넣습니다.


 

이렇게 하면 데이터가 복구됩니다. 참고로 권한이 부족하면 sys 를 가져올 수 없다고 나오는데 적절한 권한을 주시기 바랍니다.

 

 

0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

자유게시판

번호 제목 글쓴이 날짜 조회수
11 (예능프로) Mnet 아이돌학교 - 총 11회 파아란 09-12 1,321
10 [MSSQL] Delete 명령어로 지워버린 데이터 복구하기 파아란 08-18 8,111
9 불판, 후라이팬 재코팅 업체 파아란 07-14 2,698
8 네이버 블로그 - 금신사 파아란 07-12 5,468
7 PC견적 - 170709 파아란 07-09 1,243
6 [현장영상] 파출소서 차비 1천원 얻어간 여학생…그 다음날 어떻게 했을까 파아란 07-06 1,189
5 WINDOWS 10 PRO 정품구입 - 2천원 (2$) 파아란 07-05 1,165
4 암세포 죽이는 먹거리 모음 파아란 07-03 1,283
3 집에서 즉시 치아 미백 할 수 있는 놀라운 방법 7가지 파아란 06-05 1,324
2 A780L3 보드 - 메모리, VGA 파아란 05-31 1,258
1 초아는 뭔가를 알고 있었던 것일까? 파아란 05-25 1,291