问题 Oracle编号和varchar连接


我有一个连接两个表的查询。一个表的列为varchar类型,另一个表的类型为number。我已经在3个oracle数据库上执行了我的查询,并且看到了一些我希望可以解释的奇怪结果。在两个数据库中,类似于以下工作。

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=a.col1;

在此查询中,tableA.col1的类型为number,tableB.col2的类型为varchar。这在两个数据库中工作正常,但在第三个数据库中没有。在第三个我得到(ORA-01722)错误。在第三个我需要做的事情......

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=to_char(a.col1);

这适用于所有数据库。我的问题是为什么?以上是一个简化的查询,真正的查询稍微复杂一点,并检索大量数据,因此第一个版本要快得多。如果我能在所有环境中工作,那就太好了。

有谁知道为什么这可能在某些oracle数据库中工作而不是其他没有数据类型强制转换的数据库?是否存在能够实现此类行为的全局设置?


3165
2018-02-24 23:19


起源

整理将是我的第一个猜测。 Oracle通常允许隐式转换,因此可能是一列没有传递隐式转换... - OMG Ponies
你写下了所有这些词,但你仍然无法准确解释 怎么样 第一个查询在第三个数据库中不起作用。 - APC
抱歉,我在第一个查询第三个数据库中收到ORA-01722错误 - broschb
所以我猜对了;) - APC


答案:


隐式转换失败的一个原因是连接varchar列包含非数字的数据。 Oracle通过转换字符串来处理数字到varchar2连接(在他的评论中查看Gary的引用),所以它实际执行:

select a.col1, b.somecol 
from tableA a inner join tableB b on to_number(b.col2)=a.col1;

如果tableB.col2包含非数字的值 - 似乎很可能,它毕竟是一个字符串 - 然后它会投掷 ORA-01722: invalid number。通过将数字列显式地转换为字符串,可以使Oracle的默认行为发生短路。

您在前两个环境中没有遇到此问题的事实是运气而不是配置。它可以随时打击,因为它只需要一个非数字字符串来打破查询。所以你应该在所有环境中使用显式转换运行。

至于性能,你可以构建一个基于函数的索引......

create index whatever_idx on tableA ( to_char(col1) )
/ 

16
2018-02-24 23:38



稍后 download.oracle.com/docs/cd/B19306_01/server.102/b14200/... “将字符值与数值进行比较时,Oracle会将字符数据转换为数值。” - Gary Myers
您可以将tableA中的数字转换为字符串,这样如果tableB中存在非数字字符串,则不会出错。即CAST(a.col1 AS VARCHAR(20)) - Ginja Ninja