Oracle SQL PLSQL大数字字段奇怪的行为

Oracle SQL PLSQL大数字字段奇怪的行为,oracle,plsql,numbers,colon,Oracle,Plsql,Numbers,Colon,现有的表名为TENTABLE,列largenumber是一个数字字段,未设置精度: largenumber NUMBER; 查询: select largenumber from temptable; select largenumber from temptable; 它返回: -51524845525550100000000000000000000 -51524845525550:100000000000000000000 -5152484552555010000000000000

现有的表名为TENTABLE,列largenumber是一个数字字段,未设置精度:

largenumber NUMBER;
查询:

select largenumber from temptable;
select largenumber from temptable;
它返回:

-51524845525550100000000000000000000
-51524845525550:100000000000000000000
-51524845525550100000000000000000000
但如果我这样做了

column largenumber format 999999999999999999999999999999999999999
然后

它返回:

-51524845525550100000000000000000000
-51524845525550:100000000000000000000
-51524845525550100000000000000000000
为什么有冒号

为了测试,我取了这个数字,删除冒号,并将其插入到另一个表TENTRABLE2中,并使用相同的列largenumber格式,select返回不带冒号的数字:

select largenumber from temptable2;
它返回:

-51524845525550100000000000000000000
-51524845525550:100000000000000000000
-51524845525550100000000000000000000
所以这里没有冒号

那么,原始数字字段中有什么可能导致冒号呢

在原始行中,如果我执行选择并尝试执行任何to_CHAR、REPLACE、CAST或concatenate to text操作,则会出现数字转换错误

例如,尝试生成csv:

select '"' || largenumber || '",'
FROM temptable;
将导致:

在一条评论中(在回答我的问题时),您分享了
dump(largenumber)
关于有问题的返回值

Typ=2 Len=8: 45,50,56,53,52,48,46,48
从一开始,这就意味着存储在磁盘上的数据无效(它不是
number
数据类型值的有效表示)
Typ=2
是正确的,即对于数据类型
number
。长度(8字节)是正确的(我们都可以数到8才能看到)

问题在于字节本身。我们只需要检查第一个和最后一个字节就可以看到

第一个字节是45。它对数字的符号和指数进行编码。第一位(1或0)表示符号:1表示正,0表示负。45小于128,因此第一字节中的第一位为0;所以这个数字是负数。(到目前为止,这与您所知道的预期值相符。)

但是,对于负数,最后一个字节始终是魔法值102始终。在您原始问题下的另一条评论中,康纳·麦克唐纳询问了您的平台——但这是独立于平台的,它是Oracle在任何平台上为永久存储编码数字的方式。因此,我们已经知道,您得到的
dump
值告诉我们该值无效

事实上,康纳在同一评论中给出了该数字的正确表示(根据甲骨文的数字内部表示方案)。实际上,只有最后一个字节是错误的:您的
dump
显示48,但它应该是102

你怎么能解决这个问题?如果是一次性的,只需使用
update
语句将该值替换为正确的值,然后继续。如果您的表有主键,我们将其称为
id
,然后找到此行的
id
,然后

update {your_table} set largenumber = -50...... where id = {that_id};
问题是,您的表中可能有多少这样的损坏值?如果只是一个,你可以耸耸肩;但是如果有很多(甚至是“一把”),你可能想弄清楚他们是如何到达那里的

在大多数情况下,数据库将拒绝无效值;例如,您不能简单地在
数字列中插入
'abc'
。但是有很多方法可以获取坏数据;甚至是有意的,并且以可重复的方式。因此,您必须调查错误值是如何插入的(插入时使用了什么过程)

要以可重复的方式在
number
列中插入坏数据,您可以在Oracle开发者论坛上看到以下线程:


请注意,我当时刚刚开始学习甲骨文(我在甲骨文领域还不到两个月),所以我可能在那篇文章中说了一些愚蠢的话;但是插入坏数据的方法在这里有详细的描述,并且已经过测试。这只显示了在表中插入无效内容的一种可能(而且似乎合理)方法;在您的具体案例中是如何发生的,您必须自己调查。

我无法使用SQL*Plus在我的11g上复制它。输出中没有冒号。请尝试
从{your_first_table}中选择dump(largenumber)
并向我们展示它返回的内容。
dump
函数适用于所有表达式(任何数据类型),它以原始形式精确显示磁盘上存储的内容。这可能会给我们一些线索。我选择了另一个例子。执行简单选择时的值-514548495355000000000000000000000000转储(largenumber):典型值=2 Len=8:45,50,56,53,52,48,46,48设置列项余额格式999999999999999999999999999:返回值:51454849535553:100000000000000000000@Littlefoot . 这就是我的经历。如果我手动将该值插入另一个表,它将不会有相同的行为。Windows/Linux上的dump(-514548495355000000000000000000000000)为我提供了Typ=2 Len=8:45,50,56,53,52,48,46102。你在哪个站台?