我支持的应用程序的数据存储最近已从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调用中进行一些数据转换调用以解决此问题?
答案 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太老了,现在本身可能很难。