Oracle:ORA-01722:无效的数字

时间:2016-05-14 16:48:09

标签: oracle

我在sqlplus中运行时有一个很好用的查询:

SQL> SELECT  T_0.ID AS ATTR_1_, T_0_0.ID AS ATTR_2_,  
CASE  WHEN   ( T_0.ID=1 AND  ( T_0_0.ID=3 OR T_0_1.ID='val_1')  )  
THEN  'val_1' ELSE  'val_2' END  AS TXT, T_0_1.ID,  
CASE  WHEN  T_0.ID='boo' THEN  'boo' END  AS EXTRA_FIELD 
FROM TEST_TABLE T_0  
INNER JOIN TEST_TABLE_2 T_0_0  ON  ( T_0_0.ATTR=T_0.ID )  
INNER JOIN TEST_TABLE_3 T_0_1  ON  ( T_0_1.ID = T_0_0.ID )  
WHERE  (  ( T_0.ID=1 AND T_0_0.ID=3 )  
OR T_0_1.ID=2 OR T_0_0.TXT='val_2');

no rows selected

虽然它没有返回任何内容,但它仍然有效并且不会导致错误。但是,当我在Python中使用绑定做同样的事情时,我收到此错误消息:

 cx_Oracle.DatabaseError: ORA-01722: invalid number

在我执行cursor.execute之前,这就是我的查询在Python中的显示方式:

SELECT  T_0.ID AS ATTR_1_, T_0_0.ID AS ATTR_2_,  
CASE  WHEN   ( T_0.ID=:TXT_ AND  ( T_0_0.ID=:TXT__ OR T_0_1.ID=:TXT___ )  )  
THEN  :TXT___ ELSE  :TXT____ END  AS TXT, T_0_1.ID,  
CASE  WHEN  T_0.ID=:EXTRA_FIELD THEN  :EXTRA_FIELD END  AS EXTRA_FIELD 
FROM TEST_TABLE T_0  
INNER JOIN TEST_TABLE_2 T_0_0  ON  ( T_0_0.ATTR=T_0.ID )  
INNER JOIN TEST_TABLE_3 T_0_1  ON  ( T_0_1.ID = T_0_0.ID )  
WHERE  (  ( T_0.ID=:ID AND T_0_0.ID=:ID_ )  
OR T_0_1.ID=:ID__ OR T_0_0.TXT=:TXT )

查询只是一个字符串双引号“SELECT ...”。这就是具有绑定变量的字典的样子:

OrderedDict([('TXT_', 1), ('TXT__', 3), ('TXT___', 'val_1'), 
('TXT____', 'val_2'), ('EXTRA_FIELD', 'boo'), ('ID', 1), 
('ID_', 3), ('ID__', 2), ('TXT', 'val_2')])

所以,你可以看到我有一个完美的字典 - 数字值只是没有引号的数字,字符串值只是带单引号的字符串。我知道,你会询问表格的架构。所以,这是:

SQL> SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE
TABLE_NAME = 'TEST_TABLE';

COLUMN_NAME
------------------------------
DATA_TYPE
------------------------------
ID
NUMBER

SQL> SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE
TABLE_NAME = 'TEST_TABLE_2';

COLUMN_NAME
------------------------------
DATA_TYPE
------------------------------
ATTR
NUMBER

ID
NUMBER

TXT
VARCHAR2

SQL> SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS 
WHERE TABLE_NAME = 'TEST_TABLE_3';

COLUMN_NAME
------------------------------
DATA_TYPE
------------------------------
ID
NUMBER

因此,似乎同一个查询在控制台中运行良好,但在使用Python时不起作用。那是为什么?

修改

这是一个证明 - 两个控制台窗口的屏幕。在第一个控制台中我在sqlplus中运行查询,在第二个控制台中我打印sql查询和字典,用于绑定变量:

enter image description here

修改

哦,它更有趣。我能够在Oracle shell中重现此错误,它看起来像Oracle 11c错误。所以,看看这个:

enter image description here

请注意ID字段具有NUMBER类型的事实。然后注意这两个屏幕:

enter image description here

在上面的屏幕中,您可以看到一切正常。但是,如果我们通过将OR T_0_1.ID=2添加到WHERE部分来稍微更改它,那么它会中断:

enter image description here

因此,即使在Oracle shell中,此问题也是可重现的。您可以使用我上面提供的架构来完成它。

修改

我更新了我的问题主题,因为它与Python无关。 Oracle本身的整个问题。

修改

顺便说一句。我的最后评论与我调查的开头部分并不矛盾。问题是,如果我在TEST_TABLE_3中有一些数据,那么查询就会中断。如果我删除数据,那么就开始工作了。这是一个很好的证据: enter image description here

数据如何影响查询的正确性?

1 个答案:

答案 0 :(得分:1)

在你的陈述的最后一行正下方的最后一个屏幕上

CASE WHEN ( T_O.ID=1 AND ( T_0_0.ID=3 OR T_0_1.ID='VAL_1') )  

有一个星号(现在它有帮助,但有时它可能导致错误的方向)显示遇到问题的位置

T_0_1.ID='VAL_1' 
表ID列中的

是Number类型。 ' VAL_1' - 是Varchar。

正如比较规则所述:

  

将字符值与数值进行比较时,Oracle会将字符数据转换为数值。

见(https://docs.oracle.com/database/121/SQLRF/sql_elements002.htm#SQLRF00214

当oracle遇到这个时,它会尝试将你的字符串转换为数字 - 然后你就会得到错误

  

数据如何影响查询的正确性?

如果表中没有数据 - 表中没有返回记录,因此无需检查列的值是否相等 - 此比较未执行并且没有显示错误