【问题标题】:Oracle: ORA-01722: invalid number甲骨文:ORA-01722:无效号码
【发布时间】:2016-05-14 16:48:09
【问题描述】:

我有一个查询,当我在 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

这是我的查询在 Python 中的样子,在我执行 cursor.execute 之前:

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 中有一些数据,那么查询就会中断。如果我删除数据,那么它就开始工作了。这是一个很大的证明:

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

【问题讨论】:

  • 您是否尝试缩小范围,看看问题出在哪里?比如注释掉“INNER JOIN”这两条线,重新编译试试;您仍然收到错误消息吗?这会告诉你去哪里看。
  • 不,我还没试过。
  • 我的查询是由自动测试之一生成的。现在我将尝试对其进行硬编码。
  • 顺便说一句,我不能注释掉最后两个 JOINS,因为我在 SELECT ... 部分中使用了连接表中的字段。
  • 我设法缩小了范围。整个问题仅由查询的 WHERE 部分引起。如果我将其删除并删除相应的绑定,则可以。但是我的绑定有什么问题?

标签: oracle


【解决方案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 列是数字类型。 'VAL_1' - 是 Varchar。

如比较规则所述:

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

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

当 oracle 遇到这种情况时,它会尝试将您的字符串转换为数字 - 您会收到错误

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

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

【讨论】:

  • 哦,我明白了。但这听起来像是无稽之谈。为什么它会尝试强制转换而不是简单地将数字与字符串进行比较并确定它是错误的?我在其他几十个 RDBMS 中尝试了这个查询,它工作正常。在我知道的任何编程语言中,1 == "val_1" 都会返回 false。看起来甲骨文做的太多了,认为程序员应该思考的地方。虽然,我看到它就是这样。谢谢!
  • 嗯,就是这样。有些语言是严格的,有些不是,有些语言提供隐式数据类型转换。在这种情况下,Oracle 会尝试“帮助”您。但只是一个经验法则,不仅适用于 Oracle - 永远不要依赖隐式转换。在您的情况下 - 如果您看到有可能比较不同的数据类型 - 进行显式转换,例如 T_0_1.ID=TO_NUMBER('VAL_1')
  • 我完全同意你最后的建议。事实上,这正是我对甲骨文的期望。它的隐式转换(当你甚至不想要它时)不透明,而且相当具有误导性。
  • @Jacobian - 很高兴你得到了答案。不过,我不得不在数据类型检查方面不同意你的看法;大多数“专业级”语言强制执行严格的数据类型,这意味着代码甚至无法编译,更不用说在运行时返回任何内容了。
  • @mathguy。你说得有道理。虽然我认为没有什么可不同意的,因为也有几十种“专业级”的动态类型语言。至于正在讨论的主题,我对它应该如何工作的感觉是基于我在其他 RDBMS 中看到的,包括 MySQL、PostgreSQL 和 SQLite。
猜你喜欢
  • 2019-08-09
  • 2023-03-15
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多