2

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

4

4 回答 4

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

SELECT 可以正常工作,但在对象资源管理器中显示 Edit Top 200 Rows 不会:

无法编辑数据

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

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

Precision   Storage bytes
1 - 9   5
10-19   9
20-28   13
29-38   17

如果我们检查 .Net(SSMS 是托管应用程序)十进制精度表,我们可以很快看到问题的症结所在:精度是28-29 位有效数字。所以 .Netdecimal类型无法映射高精度(>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)

编辑前 200 名

dbcc checktable('test') with data_purity;

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

于 2012-06-08T08:38:39.217 回答
1

如上所述,这些错误通常发生在不保留精度和比例的情况下。如果您对 SSIS 感到满意,那么您可以获取那些损坏的行。采用 Martin Smith 创建的值

CREATE TABLE T(ID int ,C DECIMAL(38,0));
INSERT INTO T VALUES(1,9999999999999999999999999999999999999) 

上表重现了该错误。这里第一列代表主键。我插入了大约 1000 行,其中很少有损坏的值。下面是SSIS包设计

SSIS设计

在数据转换中,我取了有错误的列 C 并尝试将其转换为十进制(38,0)。由于会发生转换或截断错误,因此我将错误行重定向到基本上更新表的 OLEDB 命令并将列设置为 NULL

Update T
Set C=NULL
where ID=?

C 和 ID 的值将被定向到 oledb 命令。如果没有错误,那么我只是插入到一个表中(实际上不需要这样做)。如果你的主键列中有一个主键列,这将起作用桌子 。

如果日期时间列有任何错误,可以编写一个 sql 查询来验证日期时间值的格式。请通过MSDN 链接获取有效的日期时间值

   Select * from YourTable where ISDATE(Col)!=1
于 2012-06-07T04:45:07.007 回答
0

我认为您可以使用游标获取数据。请使用光标查询重试,例如以下查询:

DECLARE VerifyCursor CURSOR FOR
SELECT *
FROM MyTable
WHILE 1=1 BEGIN
    BEGIN Try
        FETCH FIRST FROM VerifyCursor INTO @Column1, @Column2, ...

        INSERT INTO @MyTable2(Column1, Column2,...)
        VALUES (@Column1, @Column2, ...)
    END TRY
    BEGIN CATCH
    END CATCH
    IF (@@FETCH_STATUS<>0) BREAK
End
OPEN VerifyCursor
CLOSE VerifyCursor
DEALLOCATE VerifyCursor
于 2012-06-07T15:46:13.563 回答
0

通过更新替换坏数据很简单:

UPDATE table SET column = NULL WHERE key_column = 'Some value'
于 2012-06-07T19:09:15.513 回答