我建议不要替换数据。这没有什么问题,只是 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 将不会:
这个问题有一个Connect Item。 SSMS 2012 仍然存在同样的问题。
如果我们查看Numeric and Decimal 的详细信息,我们会发现问题发生在一个奇怪的边界上,精度为 29,实际上 不是 SQL Server 边界(精度为 28):
Precision Storage bytes
1 - 9 5
10-19 9
20-28 13
29-38 17
如果我们检查 .Net(SSMS 是托管应用程序)decimal precision table,我们可以很快发现问题的症结所在:精度为 28-29 位有效数字。所以.Net decimal 类型无法映射高精度(>29)SQL Server numeric/decimal 类型。
这不仅会影响 SSMS 显示,还会影响您的应用程序。像 SSIS 这样的专业应用程序将使用像 DT_NUMERIC 这样的高精度表示:
DT_NUMERIC 具有固定精度和小数位数的精确数值。
此数据类型是一个 16 字节 无符号整数,带有一个单独的符号,a
范围为 0 - 38,最大精度为 38。
现在回到您的问题:您只需查看值即可发现无效条目。知道 C# 表示范围可以容纳近似值(-7.9 x 1028 到 7.9 x 1028)/(100 到 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)
dbcc checktable('test') with data_purity;
消息 2570,级别 16,状态 3,第 2 行页面 (1:145),对象 ID 中的插槽 0
837578022,索引ID 0,分区ID 2882303763115671552,分配单元ID
2882303763120062464(键入“行内数据”)。列“d”值超出
数据类型“日期时间”的范围。将列更新为合法值。