TO_CHAR(数字)函数返回ORA-01722:无效的数字

时间:2013-10-09 13:33:40

标签: sql oracle

查询:
Select To_Number(qty) From my_table Where Id=12345;
输出:
ORA-01722: invalid number
01722. 00000 - "invalid number"

查询:Select qty From my_table Where Id=12345;
输出:0.00080

查询:
Select To_Number(0.00080) From Dual;
输出:
0.00080(无错误)

这是我在Oracle面临的一个奇怪的情况。任何人都能说明为什么会这样吗?列qtyNUMBER类型。因此,很难想象它包含无效数字,但它确实发生了 我想澄清它发生在列中的特定值,尽管我们在同一列中有数千条记录 添加更多:如果我使用TO_CHAR(qty)函数,则会出现相同的错误。 qtyNUMBER类型不是VARCHAR2。实际上我们正在使用显示错误的SUM(qty)函数。因此,我去解剖,发现这一行是罪魁祸首。

4 个答案:

答案 0 :(得分:4)

我假设qty中的varchar2定义为my_table - 否则,通过调用to_number无法达到目的。如果这个假设是正确的,我会打赌表格中有一些其他行qty中有非数字数据。

SQL是一种基于集合的语言,因此Oracle(或任何其他数据库)可以完全自由地按照它认为合适的顺序评估事物。这意味着在应用to_number(qty)谓词之前,Oracle完全可以自由地评估id=12345表达式。如果Oracle碰巧遇到qty值无法转换为数字的行,则会引发错误。

在特定行中可能存在一些非数字数据,其中id = 12345恰好不显示(例如控制字符)。您可以通过运行查询来检查

SELECT dump(qty, 1016) 
  FROM my_table
 WHERE id = 12345

(如果你想要十进制而不是十六进制,使用1010作为dump的第二个参数)并检查数据中是否有任何意外。

答案 1 :(得分:2)

我能看到你的唯一方法就是得到你所展示的结果,因为qty确实是一个number字段,如果它包含了损坏的数据(这就是为什么会有怀疑的原因)关于那个假设)。我还假设您的客户端正在使用前导零格式化值,但不会强制尾随零,这通常不会出现;你当然可以用to_char(.0008, '0.00000')逼迫它,但你似乎没有这样做;仍然,领先的零让我好奇。

无论如何,为了证明腐败,你可以通过PL / SQL强制将无效值输入到字段中 - 不要尝试使用真实数据或你关心的表:

create table t42(qty number);

table T42 created.

declare
  n number;
begin
  dbms_stats.convert_raw_value('bf0901', n);
  insert into t42 (qty) values (n);
end;
/

anonymous block completed

select qty from t42;

       QTY
----------
    .00080 

select to_number(qty) from t42;

Error starting at line : 12 in command -
select to_number(qty) from t42
Error report -
SQL Error: ORA-01722: invalid number
01722. 00000 -  "invalid number"

注意普通查询显示了预期的数字 - 虽然尾随零,没有前导零 - 并且通过to_number()运行它会抛出ORA-01722。除了领先的零,这就是你所展示的。

它也会因to_char()而失败,如问题标题所示:

select to_char(qty) from t42;

Error starting at line : 13 in command -
select to_char(qty) from t42
Error report -
SQL Error: ORA-01722: invalid number

......这是有道理的;你的to_number()正在进行隐式转换,所以它实际上是to_number(to_char(qty)),而且我认为它是实际生成错误的隐式to_char()

您的评论建议您有一个正在加载和删除数据的进程。确切地看到它正在做什么,以及它是否可能引入腐败将是有趣的。这种效果可以通过OCI实现,因为数据库将相信它传递的数据是有效的,就像在上面的PL / SQL示例中一样。有错误报告表明imp也可能导致腐败。因此,加载过程的细节可能很重要,确切的数据库版本和平台也是如此。

答案 2 :(得分:1)

我遇到了几乎相同的问题。我发现神秘数字的行为与dump()之后的正常数字不同。例如,假设我的qty = 500(数据类型:number(30,2)),那么:

select dump(qty) from my_table where Id=12345;

Typ=2 Len=3: 194,6,1

select dump(500.00) from dual;

Typ=2 Len=2: 194,6

如果我们知道如何存储数字数据类型(如果没有,请访问http://translate.google.com/translate?langpair=zh-CN%7Cen&hl=zh-CN&ie=UTF8&u=http%3A//www.eygle.com/archives/2005/12/how_oracle_stor.html),我们可以发现在神秘中存在拖尾零(Typ=2 Len=3: 194,6,1中的最后一个“1”)号。

所以我做了一个消除尾部零点的技巧,它适用于这个问题。

select dump(trunc(qty+0.001,2)) from my_table where Id=12345;

Typ=2 Len=2: 194,6

希望有人解释深层机制。

答案 3 :(得分:0)

试试这个:

Select To_Number(trim(qty)) From my_table Where Id=12345;