Oracle SQL PLSQL 大数字段奇怪行为

Oracle SQL PLSQL large number field strange behavior

现有 table 称为 temptable,列 largenumber 是一个 NUMBER 字段,没有设置精度:

largenumber NUMBER;

查询:

select largenumber from temptable;

它returns:

-51524845525550100000000000000000000

但如果我这样做

column largenumber format 999999999999999999999999999999999999999

然后

select largenumber from temptable;

它returns:

-51524845525550:100000000000000000000

为什么会有冒号?

为了测试,我取了数字,删除了冒号,并将其插入到另一个 table temptable2,并做了相同的列大数格式,select returns 不带冒号的数字:

select largenumber from temptable2;

它returns:

-51524845525550100000000000000000000

所以这里没有冒号。

那么原始数字字段中可能是什么导致冒号?

在原始行中,如果我执行 select 并尝试执行任何 TO_CHAR、REPLACE、CAST 或连接到文本,则会出现数字转换错误。

例如,尝试生成一个 csv:

select '"' || largenumber || '",'
FROM temptable;

会导致:

ORA-01722 ("invalid number") error occurs when an attempt is made to convert a character string into a number, and the string cannot be converted into a valid number

在评论中(回答我的问题),您分享了 dump(largenumber) 违规值 returns

Typ=2 Len=8: 45,50,56,53,52,48,46,48

从一开始,这意味着存储在磁盘上的数据无效(它不是 number 数据类型值的有效表示)。 Typ=2 是正确的,即数据类型 number。长度(8 字节)是正确的(我们都可以数到八)。

错误的是字节本身。而且,我们只需要检查第一个和最后一个字节就可以看到。

第一个字节是 45。它对您的数字的符号和指数进行编码。第一位(1 或 0)表示符号:1 表示正数,0 表示负数。 45小于128,所以第一个字节的第一位为0;所以这个数字是负数。 (到目前为止,这符合您对 intended 值的了解。)

但是,对于负数,最后一个字节 始终 神奇值 102。始终。在您原始问题下的另一条评论中,Connor McDonald 询问了您的平台 - 但这是平台无关的,这是 Oracle 如何在任何平台上编码永久存储的数字。因此,我们已经知道您获得的 dump 值告诉我们该值无效。

事实上,Connor 在同一条评论中给出了该数字的正确表示(根据 Oracle 的数字内部表示方案)。事实上,只是最后一个字节是错误的:你的 dump 显示 48,但它应该是 102。

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

update {your_table} set largenumber = -50...... where id = {that_id};

问题是,您的 table 中可能有多少这样的损坏值?如果只是一个,你可以不予理会;但如果它很多(甚至是“少数”),您可能想首先弄清楚它们是如何到达那里的。

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

有关以重复table 方式在 number 列中插入错误数据的简单方法,您可以在 Oracle 开发人员论坛上查看此主题:https://community.oracle.com/tech/developers/discussion/3903746/detecting-invalid-values-in-the-db

请注意,我当时刚刚开始学习 Oracle(不到两个月),所以我可能在该线程中说了一些愚蠢的话;但是那里详细描述了插入错误数据的方法,并且已经过测试。这只显示了一种可能的(而且是合理的!)在 table 中插入无效内容的方法;在你的具体情况下它是如何发生的,你必须自己调查。