我在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查询和字典,用于绑定变量:
修改
哦,它更有趣。我能够在Oracle shell中重现此错误,它看起来像Oracle 11c错误。所以,看看这个:
请注意ID
字段具有NUMBER
类型的事实。然后注意这两个屏幕:
在上面的屏幕中,您可以看到一切正常。但是,如果我们通过将OR T_0_1.ID=2
添加到WHERE部分来稍微更改它,那么它会中断:
因此,即使在Oracle shell中,此问题也是可重现的。您可以使用我上面提供的架构来完成它。
修改
我更新了我的问题主题,因为它与Python无关。 Oracle本身的整个问题。
修改
顺便说一句。我的最后评论与我调查的开头部分并不矛盾。问题是,如果我在TEST_TABLE_3中有一些数据,那么查询就会中断。如果我删除数据,那么就开始工作了。这是一个很好的证据:
数据如何影响查询的正确性?
答案 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遇到这个时,它会尝试将你的字符串转换为数字 - 然后你就会得到错误
数据如何影响查询的正确性?
如果表中没有数据 - 表中没有返回记录,因此无需检查列的值是否相等 - 此比较未执行并且没有显示错误