如何查询列中包含<无法读取数据>的行?

Dev*_*Dev 1 database sql-server corruption

我有一个SQL表,其中一些列,在SQL Server管理器中查看时,包含<Unable to read data>.有谁知道如何查询<Unable to read data>?我可以单独修改此列中的数据update table set column = NULL where key = 'value',但是如何查找此错误数据是否存在其他行?

Rem*_*anu 9

我建议不要替换数据.它没有任何问题,只是SSM无法在"编辑"面板中正确显示它.根据您的描述,数据库本身的数据非常好.

此脚本显示问题:

create table test (id int not null identity(1,1) primary key, 
    large_value numeric(38,0));
go

insert into test (large_value) values (1);
insert into test (large_value) values (12345678901234567890123456789012345678);
insert into test (large_value) values (1234567890123456789012345678901234567);
insert into test (large_value) values (123456789012345678901234567890123456);
insert into test (large_value) values (12345678901234567890123456789012345);
insert into test (large_value) values (1234567890123456789012345678901234);
insert into test (large_value) values (123456789012345678901234567890123);
insert into test (large_value) values (12345678901234567890123456789012);
insert into test (large_value) values (1234567890123456789012345678901);
insert into test (large_value) values (123456789012345678901234567890);
insert into test (large_value) values (12345678901234567890123456789);
insert into test (large_value) values (NULL);
go

select * from test;
go
Run Code Online (Sandbox Code Playgroud)

SELECT将正常工作,但在对象资源管理器中显示编辑前200行不会:

UnableToEditData

此问题有一个连接项.SSMS 2012仍然存在同样的问题.

如果我们查看Numeric和Decimal细节,我们会看到问题出现在一个奇怪的边界,精度29实际上不是 SQL Server边界(精度28是):

Precision   Storage bytes
1 - 9   5
10-19   9
20-28   13
29-38   17
Run Code Online (Sandbox Code Playgroud)

如果我们检查.Net(SSMS是托管应用程序)十进制精度表,我们可以快速查看问题的关键所在:精度是28-29位有效数字.因此.Net decimal类型无法映射高精度(> 29)SQL Server numeric/ decimal类型.

这不仅会影响SSMS显示,还会影响您的应用程序.像SSIS这样的专业应用程序将使用高精度表示,如DT_NUMERIC:

DT_NUMERIC 具有固定精度和比例的精确数值.此数据类型是一个16字节无符号整数,带有单独的符号,比例为0 - 38,最大精度为38.

现在回到您的问题:只需查看值即可发现无效条目.知道C#表示范围可以容纳近似值(-7.9 x 10 28到7.9 x 10 28)/(10 0到28)`(范围取决于比例),您可以搜索每列范围之外的值(要在其间搜索的实际值取决于列比例).但这引出了"用什么来取代数据?"的问题.

我建议使用专用工具进行导入导出,这些工具能够处理高精度数值.SSIS是明显的候选人.但即使是适度的bcp.exe也符合要求.

顺便说一句,如果您的值实际上是不正确的(即真正的损坏),那么我建议运行DBCC CHECKTABLE (...) WITH DATA_PURITY:

DATA_PURITY

导致DBCC CHECKDB检查数据库中是否存在无效或超出范围的列值.例如,DBCC CHECKDB检测日期和时间值大于或小于datetime数据类型的可接受范围的列; 或者带有无效的比例或精度值的十进制或近似数值数据类型列.

对于在SQL Server 2005及更高版本中创建的数据库,默认情况下会启用列值完整性检查,并且不需要DATA_PURITY选项.对于从早期版本的SQL Server升级的数据库,默认情况下不启用列值检查,直到DBCC CHECKDB WITH DATA_PURITY在数据库上运行时没有错误.在此之后,DBCC CHECKDB默认检查列值完整性.

问:如何在datetime列中出现此问题?

use tempdb;
go

create table test(d datetime)

insert into test (d) values (getdate())

select %%physloc%%, * from test;

-- Row is on page  0x9100000001000000

dbcc traceon(3604,-1);

dbcc page(2,1,145,3);

Memory Dump @0x000000003FA1A060
0000000000000000:   10000c00 75f9ff00 6aa00000 010000             ....uùÿ.j .....
Slot 0 Column 1 Offset 0x4 Length 8 Length (physical) 8

dbcc writepage(2,1,145, 100, 8, 0xFFFFFFFFFFFFFFFF)
Run Code Online (Sandbox Code Playgroud)

编辑前200名

dbcc checktable('test') with data_purity;
Run Code Online (Sandbox Code Playgroud)

消息2570,级别16,状态3,行2页面(1:145),对象ID 837578022中的插槽0,索引ID 0,分区ID 2882303763115671552,分配单元ID 2882303763120062464(类型"行内数据").列"d"值超出数据类型"datetime"的范围.将列更新为合法值.

  • @MartinSmith 查看我的更新。孩子们,不要在家里这样做:) 不要自愿使用“DBCC WRITEPAGE”破坏您的数据库... (2认同)