我知道 Oracle(我正在开发 Oracle11gR2)可以隐式地将数据类型相互转换(如果它能够这样做的话)。例如,如果我尝试将数字插入 varchar 区域,它会隐式地将数字转换为 varchar,反之亦然,如果 varchar 是有效数字,则它会转换为数字。
Oracle 也在连接上执行这种隐式转换。如果我将数字列连接到 varchar 列,它会隐式地将 varchar 转换为数字并完成查询。但是,如果 varchar 列中存在任何无效数字,则会抛出一个错误。ORA-01722 : Invalid Number您可以通过运行以下代码来查看此设置:
create table test_1(
id varchar2(20),
val number);
create table test_2(
id number,
name varchar2(20)
);
insert into test_1 values ('abc', 10);
insert into test_1 values ('1', 11);
insert into test_2 values (1,'abc');
insert into test_2 values (2,'def');
-- Throw error
select
*
from
test_1, test_2
where
test_1.id = test_2.id
-- work
select
test_1.id, val, name
from
test_1, test_2
where
test_1.id = test_2.id
and test_1.id = '1'
Run Code Online (Sandbox Code Playgroud)
您还可以在以下位置查看并运行示例:http://sqlfiddle.com/#! 4/fdce3/9/0
现在我的问题是,是否有任何选项或配置参数可以强制 Oracle 将隐式转换为 varchar 而不是数字?或者确切地看到无效数字的错误来源(哪个列或哪个连接)?
我知道我可以明确地进行转换以避免错误。如下所示,但我不希望将其作为解决方案。
select
*
from
test_1, test_2
where
test_1.id = to_char(test_2.id)
Run Code Online (Sandbox Code Playgroud)
您也可以访问http://sqlfiddle.com/#!4/fdce3/10来查看上面的代码是否正常工作。
谢谢
“可以显式地进行转换以避免错误......我不希望将其作为解决方案”。
那么您不想采用良好的做法吗?为什么不呢?不过,如果您将数字列与字符串列进行比较,也许那匹马已经逃跑了。
无论如何。ORA-01722 是一个告诉我们一些有用信息的数据库:它告诉我们“您期望test1.id是数字,但您应该知道它包含非数字值”。现在我们可以解决这个错误了。
首先,这是对的吗?我们是否期望test1.id包含非数字值?如果答案是“否”,那么我们就存在数据质量问题(更不用说数据建模问题),我们应该提出错误。
但是,如果我们知道test1.id可以合法包含非数字字符串,那么我们必须相应地编写查询。这意味着我们需要应用to_char()WHERE 子句的另一端。这不仅可以处理错误,还可以向查看查询的未来同事挥动一个小标志:“顺便说一句,test1.id包含非数字值:疯狂,嗯?”
“是否有任何选项或配置参数可以强制 Oracle 将隐式转换为 varchar 而不是数字?”
抑制异常总是一个坏主意。当出现问题时,我们需要知道,以便我们能够正确处理。
“是否有任何选项或配置参数可以......准确地查看无效数字的错误来源(哪个列或哪个连接)?”
可惜没有。公平地说,期望您熟悉您正在使用的数据模型并不是没有道理的。但是,如果您不知道哪些列导致了问题,则除了查看数据字典(即all_tab_columns)之外,别无选择。
如果您想找出字符串列中的哪些行包含非数字值,那么您将需要查询它。Oracle 12cR2 中有一个非常简洁的VALIDATE_CONVERSION()函数。了解更多。如果您使用的是早期版本,那么您需要编写自己的版本,例如另一个 StackOverflow 线程中的函数。
“我在 ETL 团队工作,我对源数据模型没有任何控制权。”
事实上,ETL 的最大问题之一是处理来自源系统的不良数据。有多种方法,例如将数据加载到临时表中,验证它,然后根据其质量将其发布到最终表或隔离表。或者,我们可以使用 DML 错误日志记录;这至少会隔离抛出异常的记录。了解更多。