【发布时间】:2019-03-24 04:19:01
【问题描述】:
我收到一个对我来说没有意义的 Oracle Invalid Number 错误。我了解what this error means,但在这种情况下不应该发生这种情况。抱歉这个问题太长了,但请耐心等待,我可以彻底解释一下。
我有一个存储不同来源的 ID 的表,其中一些 ID 可以包含字母。因此,该列是VARCHAR。
其中一个来源具有数字 ID,我想加入该来源:
SELECT *
FROM (
SELECT AGGPROJ_ID -- this column is a VARCHAR
FROM AGG_MATCHES -- this is the table storing the matches
WHERE AGGSRC = 'source_a'
) m
JOIN SOURCE_A a ON a.ID = TO_NUMBER(m.AGGPROJ_ID);
在大多数情况下,这是可行的,但取决于随机因素,例如 select 子句中的列,如果它使用左连接或内连接等,我将开始看到 Invalid Number 错误。
我已多次验证AGG_MATCHES 中的所有条目,其中AGGSRC = 'source_a' 在AGGPROJ_ID 列中不包含非数字字符:
-- this returns no results
SELECT AGGPROJ_ID
FROM AGG_MATCHES
WHERE AGGSRC = 'source_a' AND REGEXP_LIKE(AGGPROJ_ID, '[^0-9]');
我知道 Oracle 基本上会在内部重写查询以进行优化。回到第一个 SQL 示例,我最好的猜测是,根据整个查询的编写方式,在 某些情况 Oracle 会尝试在子查询之前执行 JOIN .换句话说,它试图将整个AGG_MATCHES 表连接到SOURCE_A,而不仅仅是子查询返回的子集。如果是这样,那么AGGPROJ_ID 列中会有包含非数值的行。
有谁知道这是否是导致错误的原因?如果是这个原因,我有没有强制 Oracle 先执行子查询部分,所以它只是试图加入 AGG_MATCHES 表的子集?
更多背景知识:
这显然是一个简化的例子来说明问题。 AGG_MATCHES 表用于存储不同来源(即项目)之间的“匹配”。换句话说,就是说sourceA中的项目与sourceB中的项目相匹配。
我没有一遍又一遍地编写相同的 SQL,而是为我们常用的源创建了视图。这个想法是有一个包含两列的视图,一列用于 SourceA,一列用于 SourceB。出于这个原因,我不想在源表的ID 列上使用TO_CHAR,因为开发人员每次进行连接时都必须记住这样做,并且我正在尝试删除代码复制。另外,由于SOURCE_A中的ID是一个数字,所以我觉得任何存储SOURCE_A.ID的视图都应该继续将其转换为数字。
【问题讨论】:
-
那么当你遇到一个非数字id值的记录你应该怎么做呢?
-
@OldProgrammer 我在将记录插入
AGG_MATCHES时进行了验证,以确保AGGSRC = 'source_a'时仅提供数字ID -
@OldProgrammer 同样,
'source_a'不应该有非数字 id 值,因为SOURCE_A.ID是一个NUMBER列。让这件事变得棘手的是SOURCE_B.ID是VARCHAR。作为记录,我继承了这个数据库,如果我自己从头开始构建它,一开始就不会使用非数字 ID。 -
然而,真正的问题是,为什么要在 varchar 列中存储一个数字?
-
@a_horse_with_no_name 我想我在问题中解释了这一点。有多个源表,其中一些源表具有非数字 ID,因此匹配表必须支持非数字 ID,具体取决于源。