在Oracle字符串连接中将非常大的数字转换为varchar

时间:2017-04-10 15:22:16

标签: oracle

我支持的应用程序的数据存储最近已从Oracle 9i迁移到12c。在此迁移之后,偶然的查询中出现了一个问题,即在字符串连接中检索非常大的数字。假设一个表定义

mytable{
test1 number,
test2 number
}

一行带值

test1 = 100000000000000000000 and test2=100

在9i中,我可以运行查询select test1||','||test2 from mytable并获得结果

100000000000000000000,100

在12c我得到ORA-01722:无效的号码 01722. 00000 - "无效数字" *原因:指定的号码无效。 *操作:指定有效数字。

以下是堆栈跟踪的相关部分:  java.sql.SQLSyntaxErrorException:ORA-01722:无效数字

    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:447)
    at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:951)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:513)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:227)
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
    at oracle.jdbc.driver.T4CStatement.doOall8(T4CStatement.java:195)
    at oracle.jdbc.driver.T4CStatement.executeForDescribe(T4CStatement.java:876)
    at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1175)
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1296)
    at oracle.jdbc.driver.OracleStatement.executeQuery(OracleStatement.java:1498)
    at oracle.jdbc.driver.OracleStatementWrapper.executeQuery(OracleStatementWrapper.java:406)

这是两个代表性列的转储,第一个具有非常大的值,来自12c:Typ = 2 Len = 3:cb,2,1 Typ = 2 Len = 5:bb,36,48 ,1A,4A

来自9i的相同转储:Typ = 2 Len = 3:cb,2,1 Typ = 2 Len = 5:bc,a,12,52,25

由于字符串连接在数据库中,我认为这种行为不受sqlplus或其他客户端配置的影响,而是在服务器本身中确定。是否有一些配置可以在12c中更改,或者我应该在select调用中进行一些数据转换调用以解决此问题?

1 个答案:

答案 0 :(得分:2)

不幸的是,您的数据库中似乎有损坏的数据;并且听起来它在9i中已经腐败,而不是在迁移过程中损坏(可能是通过exp / imp)。

您可以通过强制插入无效数据来证明问题(不要在真实表格上执行此操作):

SQL> create table mytable(test1 number, test2 number);

Table created.

SQL> declare
  l_test1 number;
  l_test2 number;
begin
  dbms_stats.convert_raw_value('cb0201', l_test1);
  dbms_stats.convert_raw_value('bc0a125225', l_test2);
  insert into mytable(test1, test2) values (l_test1, l_test2);
end;
/

PL/SQL procedure successfully completed.

SQL> select test1||','||test2 from mytable;
select test1||','||test2 from mytable
       *
ERROR at line 1:
ORA-01722: invalid number

SQL> select dump(test1, 1016) as d1, dump(test2, 1016) as d2 from mytable;

D1
--------------------------------------------------------------------------------
D2
--------------------------------------------------------------------------------
Typ=2 Len=3: cb,2,1
Typ=2 Len=5: bc,a,12,52,25

在9i中运行相同的测试不会抛出相同的错误,即使表中的原始数据无效:

SQL> select test1||','||test2 from mytable;

TEST1||','||TEST2
--------------------------------------------------------------------------------
100000000000000000000,.0000000009178136

1 row selected.

SQL> select dump(test1, 1016) as d1, dump(test2, 1016) as d2 from mytable;

D1
--------------------------------------------------------------------------------
D2
--------------------------------------------------------------------------------
Typ=2 Len=3: cb,2,1
Typ=2 Len=5: bc,a,12,52,25

显示为cb,2,1的转储值不应该包含最后一个字节(1)。如果转储实际数字,则在任一版本中,您都会得到:

SQL> select dump(100000000000000000000, 1016) from dual;

DUMP(100000000000
-----------------
Typ=2 Len=2: cb,2

并且如果使用该数字填充表,而不是强制使用损坏的值,它也会在两个版本中按预期工作。

9i中先前的导出/导入可能导致了问题,或者OCI程序导致了问题(可能还有其他方法)。在不知道数据何时以及如何被破坏的情况下,我不得不质疑你可以信任多少,以及它是如何可以恢复的。有可能将其清理干净,但不知道正确的值是什么,听起来有点危险。

您可能需要让Oracle支持人员帮助您进一步分析问题并提出恢复方法;虽然9i太老了,现在本身可能很难。