如何避免隐式转换中的无效数字

时间:2018-01-13 08:19:53

标签: sql oracle

我知道Oracle(我正在研究Oracle11gR2)可以隐式地将数据类型转换为彼此,如果能够这样做的话。例如,如果我尝试在varchar区域中插入一个数字,它会隐式地将数字转换为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'

您还可以在http://sqlfiddle.com/#!4/fdce3/9/0

上查看和运行示例

现在我的问题,是否有任何选项或配置参数强制Oracle将此隐式转换为varchar而不是number?或者确切地看到无效数字的错误来源(哪一列或哪个连接)?

我知道我可以明确地进行转换以避免错误。如下所示,但我不希望这作为解决方案。

select 
  * 
from
 test_1, test_2
where
 test_1.id = to_char(test_2.id)

您也可以访问http://sqlfiddle.com/#!4/fdce3/10以查看上述代码是否正常运行。

由于

2 个答案:

答案 0 :(得分:4)

  

“可以明确地进行转换以避免错误......我不希望这作为解决方案”。

所以你不想使用好的做法?为什么不呢?但是,如果您将数字列与字符串列进行比较,那么马可能已经用螺栓固定了。

安美居。 ORA-01722是一个告诉我们一些有用信息的数据库:它告诉我们'你期望test1.id是数字,但你应该知道它包含非数字值。现在我们可以解决错误。

首先,这是对的吗?我们希望test1.id包含非数字值吗?如果答案是“否”,那么我们就会遇到数据质量问题(更不用说数据建模问题),我们应该提出一个错误。

但是如果我们知道test1.id可以合法地包含非数字字符串,那么我们必须相应地编写我们的查询。这意味着我们需要在WHERE子句的另一端应用to_char()。这不仅可以处理错误,还可以向未来的同事看一下查询:'顺便说一下,test1.id包含非数字值:疯了,嗯?'

  

“是否有任何选项或配置参数来强制Oracle将此隐式转换为varchar而不是数字?”

抑制异常总是一个坏主意。我们需要知道什么时候出现问题,以便我们能够妥善处理。

  

“是否有任何选项或配置参数...准确查看无效数字的错误来源(哪一列或哪个连接)?”

唉不。公平地说,期望您熟悉您正在使用的数据模型并不是不合理的。但是,如果您不知道哪些列导致了问题,则无法通过数据字典(即all_tab_columns)。

如果要查找字符串列中的哪些行包含非数字值,则需要查询它。在Oracle 12cR2中,有一个非常整洁的VALIDATE_CONVERSION()函数。 Find out more。如果您使用的是早期版本,则需要编写自己的版本,例如t his function in another StackOverflow thread

  

“我在ETL团队工作,我对源数据模型没有任何控制权。”

实际上,ETL最大的问题之一是处理源系统中的错误数据。有多种方法,例如将数据加载到登台表,验证它,然后根据其质量将其发布到最终表或隔离表。或者我们可以使用DML错误记录;至少会隔离抛出异常的记录。 Find out more

答案 1 :(得分:-1)

您不需要任何特殊技巧,只需通过匹配使用“仅数字”的正则表达式来加入那些“数字”的ID:

select 
  test_1.id, val, name 
from
 test_1, test_2
where
 test_1.id = test_2.id
 and regexp_like (test_1.id, '^[0-9]+$')

请参阅regexp_like documentation