Fra*_*ani -1 t-sql sql-server scripting stored-procedures data-conversion
我最近偶然发现了一篇博客文章,其中讨论了一个名为的存储过程Recover_Deleted_Data_Proc.sql,它显然可以从文件中恢复已删除的数据.log。
太阳底下并无新鲜事,我们要用fn_dblog。
重现步骤
我们首先要创建表:
--Create Table
CREATE TABLE [Test_Table]
(
[Col_image] image,
[Col_text] text,
[Col_uniqueidentifier] uniqueidentifier,
[Col_tinyint] tinyint,
[Col_smallint] smallint,
[Col_int] int,
[Col_smalldatetime] smalldatetime,
[Col_real] real,
[Col_money] money,
[Col_datetime] datetime,
[Col_float] float,
[Col_Int_sql_variant] sql_variant,
[Col_numeric_sql_variant] sql_variant,
[Col_varchar_sql_variant] sql_variant,
[Col_uniqueidentifier_sql_variant] sql_variant,
[Col_Date_sql_variant] sql_variant,
[Col_varbinary_sql_variant] sql_variant,
[Col_ntext] ntext,
[Col_bit] bit,
[Col_decimal] decimal(18,4),
[Col_numeric] numeric(18,4),
[Col_smallmoney] smallmoney,
[Col_bigint] bigint,
[Col_varbinary] varbinary(Max),
[Col_varchar] varchar(Max),
[Col_binary] binary(8),
[Col_char] char,
[Col_timestamp] timestamp,
[Col_nvarchar] nvarchar(Max),
[Col_nchar] nchar,
[Col_xml] xml,
[Col_sysname] sysname
)
Run Code Online (Sandbox Code Playgroud)
然后我们将数据插入其中:
--Insert data into it
INSERT INTO [Test_Table]
([Col_image]
,[Col_text]
,[Col_uniqueidentifier]
,[Col_tinyint]
,[Col_smallint]
,[Col_int]
,[Col_smalldatetime]
,[Col_real]
,[Col_money]
,[Col_datetime]
,[Col_float]
,[Col_Int_sql_variant]
,[Col_numeric_sql_variant]
,[Col_varchar_sql_variant]
,[Col_uniqueidentifier_sql_variant]
,[Col_Date_sql_variant]
,[Col_varbinary_sql_variant]
,[Col_ntext]
,[Col_bit]
,[Col_decimal]
,[Col_numeric]
,[Col_smallmoney]
,[Col_bigint]
,[Col_varbinary]
,[Col_varchar]
,[Col_binary]
,[Col_char]
,[Col_nvarchar]
,[Col_nchar]
,[Col_xml]
,[Col_sysname])
VALUES
(CONVERT(IMAGE,REPLICATE('A',4000))
,REPLICATE('B',8000)
,NEWID()
,10
,20
,3000
,GETDATE()
,4000
,5000
,getdate()+15
,66666.6666
,777777
,88888.8888
,REPLICATE('C',8000)
,newid()
,getdate()+30
,CONVERT(VARBINARY(8000),REPLICATE('D',8000))
,REPLICATE('E',4000)
,1
,99999.9999
,10101.1111
,1100
,123456
,CONVERT(VARBINARY(MAX),REPLICATE('F',8000))
,REPLICATE('G',8000)
,0x4646464
,'H'
,REPLICATE('I',4000)
,'J'
,CONVERT(XML,REPLICATE('K',4000))
,REPLICATE('L',100)
)
GO
Run Code Online (Sandbox Code Playgroud)
我们现在要验证数据是否存在:
--Verify the data
SELECT * FROM Test_Table
Run Code Online (Sandbox Code Playgroud)
此时我们需要创建存储过程。我无法将其粘贴到此处,因为它太长,但您可以从同一篇博客文章下载它,其中有一个Box 文件的链接。
如果查询给您带来这样的麻烦:
Msg 50000, Level 16, State 1, Procedure Recover_Deleted_Data_Proc, Line 22 [Batch Start Line 700] The compatibility level should be equal to or greater SQL SERVER 2005 (90)
Msg 50000, Level 16, State 1, Procedure Recover_Deleted_Data_Proc, Line 22 [Batch Start Line 705] The compatibility level should be equal to or greater SQL SERVER 2005 (90)
Run Code Online (Sandbox Code Playgroud)
是因为你必须逐行701注释掉708。
酷,现在让我们从该表中删除数据:
--Delete the data
DELETE FROM Test_Table
Run Code Online (Sandbox Code Playgroud)
并确认数据已被删除:
--Verify the data
SELECT * FROM Test_Table
Run Code Online (Sandbox Code Playgroud)
这是最后一步:我们需要尝试使用新安装的存储过程来恢复数据。
作者指示我们使用这两个命令之一(不要忘记更改'test'您的数据库名称):
--Recover the deleted data without date range
EXEC Recover_Deleted_Data_Proc 'test', 'dbo.Test_Table'
Run Code Online (Sandbox Code Playgroud)
或者
--Recover the deleted data it with date range
EXEC Recover_Deleted_Data_Proc 'test', 'dbo.Test_Table', '2012-06-01', '2012-06-30'
Run Code Online (Sandbox Code Playgroud)
但问题是两者都会返回此错误:
(8 rows affected)
(2 rows affected)
(64 rows affected)
(2 rows affected)
(1 row affected)
(1 row affected)
(1 row affected)
(1 row affected)
(1 row affected)
(1 row affected)
Msg 245, Level 16, State 1, Procedure Recover_Deleted_Data_Proc, Line 485 [Batch Start Line 112]
Conversion failed when converting the varchar value '0x41-->01 ; 0001' to data type int.
Run Code Online (Sandbox Code Playgroud)
如果我右键单击存储过程并单击“修改”,我在 处看不到任何特别可疑的内容Line 485。
知道为什么这个存储过程不起作用吗?
提到的转换是什么?
该代码已有 10 年历史,编写时假设 a[PAGE ID]只能表示为一对整数,例如0001:00000138- 然而,正如您所知,有时会以不同的方式表示,例如0x41-->01 ; 0001:00000138。
您可以通过在光标内添加以下内容来解决该问题:
\nIF @ConsolidatedPageID LIKE '0x%-->%;%' \nBEGIN\n SET @ConsolidatedPageID = LTRIM(SUBSTRING(@ConsolidatedPageID, \n CHARINDEX(';', @ConsolidatedPageID) + 1, 8000));\nEND\nRun Code Online (Sandbox Code Playgroud)\n但接下来的问题是,当您从盒子文件中保存过程时,它可能会变成'\xe2\x80\xa0'一些古怪的?字符。当我解决这个问题时(N'\xe2\x80\xa0'当然使用,因为 Unicode 字符应该始终具有N),我仍然收到这些错误消息:
\n\n消息 537,级别 16,状态 3,过程 Recover_Deleted_Data_Proc,第 525 行\n
\n
传递给 LEFT 或 SUBSTRING 函数的长度参数无效。\n
消息 9420,级别 16,状态 1,过程 Recover_Deleted_Data_Proc,第 651 行
\nXML 分析:第 1 行,字符 2,非法 xml 字符
经过 15 分钟尝试对意大利面进行逆向工程后,我放弃了。如果您需要恢复已删除的数据,请恢复备份。如果您没有备份,那么,这就是我们进行备份的原因。人们试图创建脆弱的脚本来弥补不进行备份的情况,这正是日志恢复供应商收取高额费用的原因。
\n顺便说一句,兼容性级别错误消息是一个转移注意力的内容,完全误导了当前编写的逻辑,并且与问题完全无关。但如果在此之前:
\nIF ISNULL(@Compatibility_Level,0)<=80\nBEGIN\n RAISERROR('The compatibility level should ... blah blah',16,1)\n RETURN\nEND\nRun Code Online (Sandbox Code Playgroud)\n你添加这个:
\nIF DB_ID(@Database_Name) IS NULL\nBEGIN\n RAISERROR(N'Database %s does not exist.',11,1,@Database_name);\n RETURN;\nEND\nRun Code Online (Sandbox Code Playgroud)\n或者只是不在脚本末尾调用这两个示例调用,因为它们取决于您拥有一个名为test,因为它们依赖于您拥有一个名为 的数据库,而显然您没有。
| 归档时间: |
|
| 查看次数: |
740 次 |
| 最近记录: |