恢复SQL Server被误删除的数据

《恢复SQL Server被误删除的数据(再扩展)》

地址:http://www.cnblogs.com/lyhabc/p/4620764.html

曾经想实现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
--创建数据库
CREATE DATABASE test
GOUSE [test]
GO--创建表
CREATE TABLE [dbo].[aa]([id] [int] IDENTITY(1,1) NOT NULL,[NAME] [nvarchar](200) NULL
) ON [PRIMARY]
GO--插入测试数据
INSERT [dbo].[aa]( [NAME] )
SELECT '你好'
GO--删除数据
Delete from 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.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'
ASDECLARE @RowLogContents VARBINARY(8000)DECLARE @TransactionID NVARCHAR(MAX)DECLARE @AllocUnitID BIGINTDECLARE @AllocUnitName NVARCHAR(MAX)DECLARE @SQL NVARCHAR(MAX)DECLARE @Compatibility_Level INTSELECT  @Compatibility_Level = dtb.compatibility_levelFROM    master.sys.databases AS dtbWHERE   dtb.name = @Database_NameIF ISNULL(@Compatibility_Level, 0) <= 80BEGINRAISERROR('The compatibility level should be equal to or greater SQL SERVER 2005 (90)',16,1)RETURNENDIF ( SELECT COUNT(*)FROM   INFORMATION_SCHEMA.TABLESWHERE  [TABLE_SCHEMA] + '.' + [TABLE_NAME] = @SchemaName_n_TableName) = 0BEGINRAISERROR('Could not found the table in the defined database',16,1)RETURNENDDECLARE @bitTable TABLE([ID] INT ,[Bitvalue] INT)
--Create table to set the bit position of one byte.INSERT  INTO @bitTableSELECT  0 ,2UNION ALLSELECT  1 ,2UNION ALLSELECT  2 ,4UNION ALLSELECT  3 ,8UNION ALLSELECT  4 ,16UNION ALLSELECT  5 ,32UNION ALLSELECT  6 ,64UNION ALLSELECT  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    RowDataAS ( 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 NULLEND ) 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 NULLEND ) * 2)ELSE NULLEND ) 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 NULLEND ) * 2 ) )ELSE NULLEND AS [VarColumnStart] ,[Slot ID]FROM     sys.fn_dblog(NULL, NULL)WHERE    AllocUnitId IN (SELECT  [Allocation_unit_id]FROM    sys.allocation_units allocunitsINNER JOIN 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)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_FromAND@Date_To )),--Use this technique to repeate the row till the no of bytes of the row.
            N1 ( n )AS ( SELECT   1UNION ALLSELECT   1),N2 ( n )AS ( SELECT   1FROM     N1 AS X ,N1 AS Y),N3 ( n )AS ( SELECT   1FROM     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 @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] = 0THEN CONVERT(NVARCHAR(1), ( SUBSTRING(NullBytes,n, 1) % 2 ))ELSE CONVERT(NVARCHAR(1), ( ( SUBSTRING(NullBytes,n, 1)/ [Bitvalue] )% 2 ))END ) --as [nullBitMap]FROM N4 AS NumsJOIN RowData AS C ON n <= NullBitMapLengthCROSS JOIN @bitTableWHEREC.[RowLogContents] = D.[RowLogContents]ORDER BY [RowLogContents] ,n ASCFORXML PATH('')), 1, 1, ''), ',', '') )FROM    RowData DIF ( SELECT COUNT(*)FROM   @DeletedRecords) = 0BEGINRAISERROR('There is no data in the log as per the search criteria',16,1)RETURNENDDECLARE @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 @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 ,( CASE WHEN leaf_offset < 1AND SUBSTRING([nullBitMap], cols.leaf_null_bit,1) = 0THEN ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) > 30000THEN 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 < 1AND SUBSTRING([nullBitMap], cols.leaf_null_bit,1) = 0THEN ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) > 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) < 30000THEN ( CASE WHEN [System_type_id] IN (35, 34, 99 ) THEN 16ELSE 24END )WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) > 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) > 30000THEN ( CASE WHEN [System_type_id] IN (35, 34, 99 ) THEN 16ELSE 24END ) --24 WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) < 30000AND ISNULL(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]) )WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) < 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) > 30000THEN 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) = 1THEN NULLELSE SUBSTRING(Rowlogcontents,( ( CASE WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) > 30000THEN 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)))) > 30000AND ISNULL(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 )THEN 16ELSE 24END ) --24 WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) > 30000AND ISNULL(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 )THEN 16ELSE 24END ) --24 WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) < 30000AND ISNULL(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])WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) < 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) > 30000THEN 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)))) > 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) < 30000THEN ( CASE WHEN [System_type_id] IN (35, 34, 99 )THEN 16ELSE 24END ) --24 WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) > 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) > 30000THEN ( CASE WHEN [System_type_id] IN (35, 34, 99 )THEN 16ELSE 24END ) --24 WHEN CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* leaf_offset* -1 ) - 1, 2)))) < 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) < 30000THEN 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)))) < 30000AND ISNULL(NULLIF(CONVERT(INT, CONVERT(BINARY(2), REVERSE(SUBSTRING([ColumnOffsetArray],( 2* ( ( leaf_offset* -1 ) - 1 ) )- 1, 2)))), 0),[varColumnStart]) > 30000THEN 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] ,0FROM    @DeletedRecords AINNER 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 = 2AND partitions.partition_id = allocunits.container_id)INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_idLEFT OUTER JOIN syscolumns ON syscolumns.id = partitions.object_idAND syscolumns.colid = cols.partition_column_idWHERE   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 ,( SELECT TOP 1ISNULL(SUM(CASE WHEN C.leaf_offset > 1THEN max_lengthELSE 0END), 0)FROM      sys.system_internals_partition_columns CWHERE     cols.partition_id = C.partition_idAND 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) = 1THEN NULLELSE SUBSTRING(Rowlogcontents,( SELECT TOP 1ISNULL(SUM(CASEWHEN C.leaf_offset > 1AND C.leaf_bit_position = 0THEN max_lengthELSE 0END), 0)FROM      sys.system_internals_partition_columns CWHERE     cols.partition_id = C.partition_idAND C.leaf_null_bit < cols.leaf_null_bit) + 5, syscolumns.length)END AS hex_Value ,[Slot ID] ,0FROM    @DeletedRecords AINNER 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 = 2AND partitions.partition_id = allocunits.container_id)INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_idLEFT OUTER JOIN syscolumns ON syscolumns.id = partitions.object_idAND syscolumns.colid = cols.partition_column_idWHERE   leaf_offset > 0ORDER BY nullbitDECLARE @BitColumnByte AS INTSELECT  @BitColumnByte = CONVERT(INT, CEILING(COUNT(*) / 8.0))FROM    @ColumnNameAndDataWHERE   [System_Type_id] = 104;WITH    N1 ( n )AS ( SELECT   1UNION ALLSELECT   1),N2 ( n )AS ( SELECT   1FROM     N1 AS X ,N1 AS Y),N3 ( n )AS ( SELECT   1FROM     N2 AS X ,N2 AS Y),N4 ( n )AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY X.n )FROM     N3 AS X ,N3 AS Y),CTEAS ( SELECT   RowLogContents ,[nullbit] ,[BitMap] = CONVERT(VARBINARY(1), CONVERT(INT, SUBSTRING(( REPLACE(STUFF(( SELECT','+ ( CASEWHEN [ID] = 0THEN CONVERT(NVARCHAR(1), ( SUBSTRING(hex_Value,n, 1) % 2 ))ELSE CONVERT(NVARCHAR(1), ( ( SUBSTRING(hex_Value,n, 1)/ [Bitvalue] )% 2 ))END ) --as [nullBitMap]FROMN4 AS NumsJOIN @ColumnNameAndDataAS C ON n <= @BitColumnByteAND [System_Type_id] = 104AND bitpos = 0CROSS JOIN @bitTableWHEREC.[RowLogContents] = D.[RowLogContents]ORDER BY [RowLogContents] ,n ASCFORXMLPATH('')), 1, 1, ''),',', '') ),bitpos + 1, 1)))FROM     @ColumnNameAndData DWHERE    [System_Type_id] = 104)UPDATE  ASET     [hex_Value] = [BitMap]FROM    @ColumnNameAndData AINNER JOIN CTE B ON A.[RowLogContents] = B.[RowLogContents]AND A.[nullbit] = B.[nullbit]/**************Check for BLOB DATA TYPES******************************/DECLARE @Fileid INTDECLARE @Pageid INTDECLARE @Slotid INTDECLARE @CurrentLSN INTDECLARE @LinkID INTDECLARE @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 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*/SELECT  LTRIM(RTRIM(REPLACE([Description], 'Deallocated', ''))) AS [PAGE ID] ,[Slot ID] ,[AllocUnitId] ,NULL AS [RowLog Contents 0] ,NULL AS [RowLog Contents 0] ,ContextFROM    sys.fn_dblog(NULL, NULL)WHERE   AllocUnitId IN (SELECT  [Allocation_unit_id]FROM    sys.allocation_units allocunitsINNER JOIN 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)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_FromAND@Date_To )GROUP BY [Description] ,[Slot ID] ,[AllocUnitId] ,ContextUNIONSELECT  [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 allocunitsINNER JOIN 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)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_FromAND@Date_To )/****************************************/OPEN Page_Data_CursorFETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,@AllocUnitID, @LCX_TEXT_MIX, @LinkID, @ContextWHILE @@FETCH_STATUS = 0BEGINDECLARE @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 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    ( SELECT    CASE SUBSTRING(@hex_pageid, 1, 2)WHEN '0x' THEN 3ELSE 0END) AS t ( pos ) IF @Context = 'LCX_PFS'BEGINDELETE  @temppagedataINSERT  INTO @temppagedataEXEC( 'DBCC PAGE(' + @DataBase_Name + ', '+ @fileid + ', ' + @pageid+ ', 1) with tableresults,no_infomsgs;'); INSERT  INTO @pagedataSELECT  @ConsolidatedPageID ,@fileid ,@pageid ,@AllocUnitID ,[ParentObject] ,[Object] ,[Field] ,[Value]FROM    @temppagedataENDELSEIF @Context = 'LCX_TEXT_MIX'BEGININSERT  INTO @ModifiedRawDataSELECT  @ConsolidatedPageID ,@fileid ,@pageid ,@Slotid ,@AllocUnitID ,NULL ,0 ,CONVERT(INT, CONVERT(VARBINARY, REVERSE(SUBSTRING(@LCX_TEXT_MIX,11, 2)))) ,@LCX_TEXT_MIX ,@LinkID ,0END    FETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,@AllocUnitID, @LCX_TEXT_MIX, @LinkID, @ContextENDCLOSE Page_Data_CursorDEALLOCATE Page_Data_CursorDECLARE @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 formatINSERT  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(( SELECTREPLACE(SUBSTRING([Value],CHARINDEX(':',[Value]) + 1,CHARINDEX('†',[Value])- CHARINDEX(':',[Value])), '†','')FROM  @pagedata CWHERE 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)FORXML PATH('')), 1, 1, ''), ' ', '')), 1, 20000) AS [Value] ,SUBSTRING(( SELECT  '0x'+ REPLACE(STUFF(( SELECTREPLACE(SUBSTRING([Value],CHARINDEX(':',[Value]) + 1,CHARINDEX('†',[Value])- CHARINDEX(':',[Value])), '†','')FROM@pagedata CWHEREB.[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)FORXML PATH('')), 1, 1, ''), ' ', '')), 7, 4) AS [Length]FROM    @pagedata BWHERE   [Object] LIKE '%Memory Dump%'GROUP BY [Page ID] ,[FILE IDS] ,[PAGE IDS] ,[ParentObject] ,[AllocUnitId]--,[Current LSN]ORDER BY [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  BSET     B.[RowLog Contents 0] = ( CASE WHEN A.[RowLog Contents 0] IS NOT NULLAND C.[RowLog Contents 0] IS NOT NULLTHEN A.[RowLog Contents 0]+ C.[RowLog Contents 0]WHEN A.[RowLog Contents 0] IS NULLAND C.[RowLog Contents 0] IS NOT NULLTHEN C.[RowLog Contents 0]WHEN A.[RowLog Contents 0] IS NOT NULLAND C.[RowLog Contents 0] IS NULLTHEN A.[RowLog Contents 0]END ) ,B.[Update] = ISNULL(B.[Update], 0) + 1FROM    @ModifiedRawData BLEFT 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 NULLOR C.[RowLog Contents 0] IS NOT NULL)UPDATE  BSET     B.[RowLog Contents 0] = ( CASE WHEN A.[RowLog Contents 0] IS NOT NULLAND C.[RowLog Contents 0] IS NOT NULLTHEN A.[RowLog Contents 0]+ C.[RowLog Contents 0]WHEN A.[RowLog Contents 0] IS NULLAND C.[RowLog Contents 0] IS NOT NULLTHEN C.[RowLog Contents 0]WHEN A.[RowLog Contents 0] IS NOT NULLAND C.[RowLog Contents 0] IS NULLTHEN A.[RowLog Contents 0]END )--,B.[Update]=ISNULL(B.[Update],0)+1FROM    @ModifiedRawData BLEFT 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] = 0LEFT 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] = 0WHERE   ( A.[RowLog Contents 0] IS NOT NULLOR C.[RowLog Contents 0] IS NOT NULL)UPDATE  @ModifiedRawDataSET     [RowLog Contents 0] = ( CASE WHEN [RowLog Len] >= 8000THEN SUBSTRING([RowLog Contents 0],15, [RowLog Len])WHEN [RowLog Len] < 8000THEN SUBSTRING([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 AINNER 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  @ColumnNameAndDataSET     [hex_Value] = ( CASE WHEN B.[RowLog Contents 0] IS NOT NULLAND C.[RowLog Contents 0] IS NOT NULLTHEN B.[RowLog Contents 0]+ C.[RowLog Contents 0]WHEN B.[RowLog Contents 0] IS NULLAND C.[RowLog Contents 0] IS NOT NULLTHEN C.[RowLog Contents 0]WHEN B.[RowLog Contents 0] IS NOT NULLAND C.[RowLog Contents 0] IS NULLTHEN B.[RowLog Contents 0]END )--,A.[Update]=A.[Update]+1FROM    @ColumnNameAndData ALEFT JOIN @ModifiedRawData B ON CONVERT(INT, CONVERT(VARBINARY(MAX), REVERSE(SUBSTRING([hex_value],5, 4)))) = B.[PAGE IDS]AND B.[Link ID] = 0LEFT JOIN @ModifiedRawData C ON CONVERT(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] IS NOT NULLOR C.[RowLog Contents 0] IS NOT NULL)UPDATE  @ColumnNameAndDataSET     [hex_Value] = [RowLog Contents 0] --,A.[Update]=A.[Update]+1FROM    @ColumnNameAndData AINNER 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  @ColumnNameAndDataSET     [hex_Value] = [RowLog Contents 0]--,A.[Update]=A.[Update]+10FROM    @ColumnNameAndData AINNER 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] = 0UPDATE  @ColumnNameAndDataSET     [hex_Value] = [RowLog Contents 0] --,A.[Update]=A.[Update]+1FROM    @ColumnNameAndData AINNER 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] = 0UPDATE  @ColumnNameAndDataSET     [hex_value] = 0xFFFE + SUBSTRING([hex_value], 9, LEN([hex_value]))--,[Update]=[Update]+1WHERE   [system_type_id] = 241CREATE TABLE [#temp_Data]([FieldName] VARCHAR(MAX) ,[FieldValue] NVARCHAR(MAX) ,[Rowlogcontents] VARBINARY(8000) ,[Row ID] INT)INSERT  INTO #temp_DataSELECT  NAME ,CASE WHEN system_type_id IN ( 231, 239 )THEN LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value)))  --NVARCHAR ,NCHARWHEN system_type_id IN ( 167, 175 )THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value)))  --VARCHAR,CHARWHEN system_type_id IN ( 35 )THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), hex_Value))) --TextWHEN system_type_id IN ( 99 )THEN LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), hex_Value))) --nText WHEN system_type_id = 48THEN CONVERT(VARCHAR(MAX), CONVERT(TINYINT, CONVERT(BINARY(1), REVERSE(hex_Value)))) --TINY INTEGERWHEN system_type_id = 52THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE(hex_Value)))) --SMALL INTEGERWHEN system_type_id = 56THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(hex_Value)))) -- INTEGERWHEN system_type_id = 127THEN CONVERT(VARCHAR(MAX), CONVERT(BIGINT, CONVERT(BINARY(8), REVERSE(hex_Value))))-- BIG INTEGERWHEN system_type_id = 61THEN CONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 100) --DATETIMEWHEN system_type_id = 58THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLDATETIME, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 100) --SMALL DATETIMEWHEN system_type_id = 108THEN CONVERT(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 = 106THEN CONVERT(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 )THEN CONVERT(VARCHAR(MAX), CONVERT(MONEY, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 2) --MONEY,SMALLMONEYWHEN system_type_id = 104THEN CONVERT(VARCHAR(MAX), CONVERT (BIT, CONVERT(BINARY(1), hex_Value)% 2))  -- BITWHEN system_type_id = 62THEN 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)))) --- FLOATWHEN system_type_id = 59THEN 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) --RealWHEN system_type_id IN ( 165, 173 )THEN ( CASE WHEN CHARINDEX(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 ( CASE WHEN CHARINDEX(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 = 36THEN CONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, hex_Value)) --UNIQUEIDENTIFIERWHEN system_type_id = 231THEN CONVERT(VARCHAR(MAX), CONVERT(SYSNAME, hex_Value)) --SYSNAMEWHEN system_type_id = 241THEN CONVERT(VARCHAR(MAX), CONVERT(XML, hex_Value)) --XMLWHEN system_type_id = 189THEN ( CASE WHEN CHARINDEX(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 ( CASE WHEN CONVERT(INT, SUBSTRING(hex_Value, 1,1)) = 56THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(SUBSTRING(hex_Value,3,LEN(hex_Value))))))  -- INTEGERWHEN CONVERT(INT, SUBSTRING(hex_Value, 1,1)) = 108THEN 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)))) --- NUMERICWHEN CONVERT(INT, SUBSTRING(hex_Value, 1,1)) = 167THEN LTRIM(RTRIM(CONVERT(VARCHAR(MAX), SUBSTRING(hex_Value,9,LEN(hex_Value))))) --VARCHAR,CHARWHEN CONVERT(INT, SUBSTRING(hex_Value, 1,1)) = 36THEN CONVERT(VARCHAR(MAX), CONVERT(UNIQUEIDENTIFIER, SUBSTRING(( hex_Value ),3, 20))) --UNIQUEIDENTIFIERWHEN CONVERT(INT, SUBSTRING(hex_Value, 1,1)) = 61THEN CONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(8000), REVERSE(SUBSTRING(hex_Value,3,LEN(hex_Value))))), 100) --DATETIMEWHEN CONVERT(INT, SUBSTRING(hex_Value, 1,1)) = 165THEN '0x'+ SUBSTRING(( CASE WHEN CHARINDEX(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 )END AS FieldValue ,[Rowlogcontents] ,[Row ID]FROM    @ColumnNameAndDataORDER 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   syscolumnsWHERE  id = OBJECT_ID(''+ @SchemaName_n_TableName+ '')FORXML 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

View Code

恢复你的数据

--恢复数据,不加时间段条件  参数:数据库名,表名
--EXAMPLE #1 : FOR ALL DELETED RECORDS
EXEC Recover_Deleted_Data_Proc 'test','dbo.aa'
GO--恢复数据,加时间段条件
--EXAMPLE #2 : FOR ANY SPECIFIC DATE RANGE
EXEC 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存储结构之堆表、行溢出

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

  

步骤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 allocunitsINNER JOIN 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)INNER JOIN sys.system_internals_partition_columns cols ON cols.partition_id = partitions.partition_idLEFT OUTER JOIN 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 ,NCHAR
WHEN system_type_id IN (231, 239) THEN  LTRIM(RTRIM(CONVERT(NVARCHAR(max),hex_Value)))--VARCHAR,CHARWHEN system_type_id IN (167,175) THEN  LTRIM(RTRIM(CONVERT(VARCHAR(max),REPLACE(hex_Value, 0x00, 0x20))))--TINY INTEGERWHEN system_type_id = 48 THEN CONVERT(VARCHAR(MAX), CONVERT(TINYINT, CONVERT(BINARY(1), REVERSE (hex_Value))))--SMALL INTEGERWHEN system_type_id = 52 THEN CONVERT(VARCHAR(MAX), CONVERT(SMALLINT, CONVERT(BINARY(2), REVERSE (hex_Value))))-- INTEGERWHEN system_type_id = 56 THEN CONVERT(VARCHAR(MAX), CONVERT(INT, CONVERT(BINARY(4), REVERSE(hex_Value))))-- BIG INTEGERWHEN system_type_id = 127 THEN CONVERT(VARCHAR(MAX), CONVERT(BIGINT, CONVERT(BINARY(8), REVERSE(hex_Value))))--DATETIMEWHEN system_type_id = 61 Then CONVERT(VARCHAR(Max),CONVERT(DATETIME,Convert(VARBINARY(max),REVERSE (hex_Value))),100)--SMALL DATETIME
WHEN system_type_id =58 Then CONVERT(VARCHAR(Max),CONVERT(SMALLDATETIME,CONVERT(VARBINARY(MAX),REVERSE(hex_Value))),100) --SMALL DATETIME--- NUMERICWHEN system_type_id = 108 THEN CONVERT(VARCHAR(MAX), CAST(CONVERT(NUMERIC(18,14), CONVERT(VARBINARY,CONVERT(VARBINARY,xprec)+CONVERT(VARBINARY,xscale))+CONVERT(VARBINARY(1),0) + hex_Value) as FLOAT))--MONEY,SMALLMONEYWHEN system_type_id In(60,122) THEN CONVERT(VARCHAR(MAX),Convert(MONEY,Convert(VARBINARY(MAX),Reverse(hex_Value))),2)--- DECIMALWHEN system_type_id = 106 THEN CONVERT(VARCHAR(MAX), CAST(CONVERT(Decimal(38,34), Convert(VARBINARY,Convert(VARBINARY,xprec)+CONVERT(VARBINARY,xscale))+CONVERT(VARBINARY(1),0) + hex_Value) as FLOAT))-- BITWHEN system_type_id = 104 THEN CONVERT(VARCHAR(MAX),CONVERT (BIT,CONVERT(BINARY(1), hex_Value)%2))--- FLOATWHEN system_type_id = 62 THEN  RTRIM(LTRIM(Str(Convert(FLOAT,SIGN(CAST(Convert(VARBINARY(max),Reverse(hex_Value)) AS BIGINT)) * (1.0 + (CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) AS BIGINT) & 0x000FFFFFFFFFFFFF) * POWER(CAST(2 AS FLOAT), -52)) * POWER(CAST(2 AS FLOAT),((CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) AS BIGINT) & 0x7ff0000000000000) / EXP(52 * LOG(2))-1023))),53,LEN(hex_Value))))--REAL
When  system_type_id =59 THEN  Left(LTRIM(STR(Cast(SIGN(CAST(Convert(VARBINARY(max),Reverse(hex_Value)) AS BIGINT))* (1.0 + (CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) AS BIGINT) & 0x007FFFFF) * POWER(CAST(2 AS Real), -23)) * POWER(CAST(2 AS Real),(((CAST(CONVERT(VARBINARY(max),Reverse(hex_Value)) AS INT) )& 0x7f800000)/ EXP(23 * LOG(2))-127))AS REAL),23,23)),8)--BINARY,VARBINARY
WHEN system_type_id In (165,173) THEN (CASE WHEN Charindex(0x,cast('' AS XML).value('xs:hexBinary(sql:column("hex_value"))', 'varbinary(max)')) = 0 THEN '0x' ELSE '' END) +cast('' AS XML).value('xs:hexBinary(sql:column("hex_value"))', 'varchar(max)') --UNIQUEIDENTIFIER
WHEN system_type_id =36 THEN CONVERT(VARCHAR(MAX),CONVERT(UNIQUEIDENTIFIER,hex_Value)) 

步骤7:

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

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


我的测试

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

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

Msg 537, Level 16, State 3, Procedure Recover_Deleted_Data_Proc, Line 525
Invalid length parameter passed to the LEFT or SUBSTRING function.Msg 9420, Level 16, State 1, Procedure Recover_Deleted_Data_Proc, Line 651
XML parsing: line 1, character 2, illegal xml character

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

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

--Recover the deleted data without date range
EXEC Recover_Deleted_Data_Proc 'test','dbo.Test_Table'
GO
--Recover the deleted data it with date range
EXEC 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 log as per the search criteria


总结

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

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

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

如有不对的地方,欢迎大家拍砖o(∩_∩)o 

支持date类型 感谢园友 dwchaoyue

EXEC Recover_Deleted_Data_Proc 'sss','dbo.testdaterecover','2014-04-23','2014-10-23'
--DROP TABLE testdaterecover
CREATE TABLE testdaterecover(dd DATE,cc DATETIME)
GO
INSERT INTO [dbo].[testdaterecover]( [dd], [cc] )
VALUES  ( GETDATE(), -- dd - dateGETDATE()  -- cc - datetime
          )SELECT CONVERT(VARCHAR(MAX),CONVERT(DATETIME, CONVERT(VARBINARY(8000),[cc])),120) FROM [dbo].[testdaterecover]DELETE [dbo].[testdaterecover]THEN CONVERT(VARCHAR(MAX), CONVERT(DATETIME, CONVERT(VARBINARY(8000), REVERSE(hex_Value))), 121) --DATETIME

View Code

2015-12-17 补充

注意:脚本中大量使用了reverse函数来进行转换,因为reverse函数的定义是返回字符串值的逆序,不是字节的逆序

那么就会导致有些数据类型是按字节逆序的,就会出错

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

在SQL Server中,sys.fn_PhysLocFormatter这个函数也是使用reverse函数进行RID逆序,当遇到81-FE之间的字节时 被认为是双字节字符组合在一起参与逆序运算

所以得出来的某些结果也是错的,详细请参考《SQL Server性能调优实战》 P115

函数的逻辑是,每个字节加上相应的位数

比如 2这个数字是在第二个字节位置的,那么公式就是2*POWER(2,8) =512

相应进制

二进制后面加8个0

十六进制后面加2个0

只要学过计算机基础都不难理解的

本文版权归作者所有,未经作者同意不得转载。

恢复SQL Server被误删除的数据相关推荐

  1. 恢复SQL Server被误删除的数据(再扩展)

    原文:恢复SQL Server被误删除的数据(再扩展) 恢复SQL Server被误删除的数据(再扩展) 大家对本人之前的文章<恢复SQL Server被误删除的数据> 反应非常热烈,但是 ...

  2. php删除sql server 2008,MSSQL_SQL Server2008 数据库误删除数据的恢复方法分享,SQL Server中误删除数据的恢复本 - phpStudy...

    SQL Server2008 数据库误删除数据的恢复方法分享 SQL Server中误删除数据的恢复本来不是件难事,从事务日志恢复即可.但是,这个恢复需要有两个前提条件: 1. 至少有一个误删除之前的 ...

  3. 【服务器数据恢复】使用碎片拼接方法恢复SQL Server数据库的数据恢复案例

    服务器数据恢复环境: 某公司一台DELL服务器,作为WEB服务器使用,安装的Windows Server操作系统,配置了SQL Server数据库: 采用了Xen Server虚拟化系统: 底层是通过 ...

  4. 转载-SQL Server各种导入导出数据方式的比较

    注:本文转载自 http://blog.csdn.net/nokiaguy/article/details/4684822 当我们建立一个数据库时,并且想将分散在各处的不同类型的数据库分类汇总在这个新 ...

  5. [转载]在SQL Server数据库之间进行数据导入导出,OPENDATASOURCE

    需要在c盘下先建立一个data.txt文件,然后在文件的第一行写上你要导出的列,不如说要导出id和name这两列,就在第一行写上 id,name 然后保存,使用下列SQL就可以了,你如果要保持原有的I ...

  6. sql server left join 重复数据原因图

    sql server left join 重复数据原因图     网购从这里开始 ( 物美价廉还等什么?!!! )

  7. SQL Server 2000安装指南及数据创建

    SQL Server 是一个关系数据库管理系统,它最初是由Microsoft Sybase 和Ashton-Tate三家公司共同开发的,于1988 年推出了第一个OS/2 版本.在Windows NT ...

  8. SQL Server 2008 批量插入数据时报错

    前几天在SQL Server 2008同步产品数据时,总是提示二进制文本被截断的错误,但是经过检查发现数据都符合格式要求. 百思不得其解,单独插入一条条数据则可以插入,但是批量导入则报错. 批量导入代 ...

  9. SQL Server创建数据库和数据的增删改查

    SQL Server创建数据库和数据的增删改查 本文是针对数据的增删改查,数据的创建 首先我们使用命令创建sql server数据库 D盘新建一个文件夹DB use master go --创建数据库 ...

最新文章

  1. 机器人时代的资本主义:21世纪的工作,收入和财富
  2. C#之windows桌面软件第六课:(上集)串口工具实现数据校验、用灯反应设备状态
  3. oracle中做数据字典,oracle中数据字典是干嘛用的啊
  4. 【图像处理】——特征匹配(SIFT特征检测器+FLANN特征匹配方法+KNN近邻最优匹配筛选)——cv.xfeatures2d.SIFT_create()sift.detectAndCompute
  5. 在探索的飞鸽传书科学的道路上
  6. C++每日练笔之时间类(基类)
  7. 硬件基础知识---(5)电阻的用法
  8. python程序按钮怎么创建_如何使用pygame创建按钮?
  9. 超过千字的文章,才统计勤写标兵
  10. 文本摘要(text summarization)任务:研究范式,重要模型,评估指标(持续更新ing...)
  11. Ubuntu系统中IPFS环境的配置
  12. python爬虫---12306获取列车座位信息
  13. Cannot open D:\Anaconda3\Scripts\pip-script.py 解决
  14. 2.04 标志寄存器
  15. 你从未见过的“地狱级”烂项目
  16. AxonFramework架构概述
  17. 雖然 甚至 though、although、even though、despite、in spite of
  18. LA2402暴力枚举+计算几何+四边形面积
  19. 如何永久关闭windows安全中心?
  20. Unity—反向动力学IK

热门文章

  1. js基础篇——localStorage使用要点
  2. 【BZOJ4231】回忆树 离线+fail树+KMP
  3. $Java-json系列(二):用JSONObject解析和处理json数据
  4. ubuntu 12.04 配置vsftpd 服务,添加虚拟用户,ssl加密
  5. 实现samba可写不可删除
  6. SIFT-FCACO算法的图像配准
  7. Servlet——简单用户登录实例+http协议解析
  8. 移动物联网技术LoRa、SigFox、NB-IoT和eMTC的发展轨迹
  9. Java之定时任务详解
  10. Linux学习笔记033_10