0

我有一些表的看法:

SELECT UM00200M.ACCOUNT_NO AS INDEX1,
          CONCAT (CONCAT (TRIM (UM00200M.PERSON_LNM), ' '),
                  TRIM (UM00200M.PERSON_FNM))
             AS INDEX2,
          DECODE (NVL (TRIM (SG00100M.PERSON_ID_CUSTOM), 0),
                  0, UM00200M.PERSON_NO,
                  SG00100M.PERSON_ID_CUSTOM)
             INDEX3,
          NULL AS INDEX4,
          'CONS_ACCTG' AS GROUPNAME
     FROM UM00200M, SG00100M
    WHERE UM00200M.PERSON_NO = SG00100M.PERSON_NO

这给了我(抱歉格式化):

Column_Name DATA_TYPE NULLABLE COLUMNT_ID COMMENTS INSERTABLE UPDATEABLE
INDEX1 NUMBER(14,0) 否 1 是 是 是
INDEX2 VARCHAR2(81) 是 2 否 否 否
索引 3 编号 是 3 否 否 否
INDEX4 VARCHAR2(0) 是 4 否 否 否
GROUPNAME CHAR(10) 是 5 否 否 否

我正在寻找所有具有 INDEX3 = 524118914 的记录

--Looking for INDEX3 = 524118914

--Fails:  01722. 00000 -  "invalid number"
Select *
from Cayenta.CAHeader 
where INDEX3 = 524118914;

--Fails:  01722. 00000 -  "invalid number"
Select *
from Cayenta.CAHeader 
where INDEX3 > 524118000 and INDEX3 < 524118999;

--Works
Select *
from Cayenta.CAHeader 
where INDEX3 > 524118000 and INDEX3 < 524999999; 

--Fails: 01722. 00000 -  "invalid number"
Select *
from Cayenta.CAHeader 
where INDEX3 > 524118000 and INDEX3 < 524999999 
ORDER BY INDEX3;

执行查询时,我没有得到预期的结果。为什么我会收到“无效号码”?

我认为这与 DECODE 函数有关,SG00100M.PERSON_ID_CUSTOM 是一个 CHAR(15 BYTE) 字段,但填充了所有数字数据。(我知道 - 糟糕的设计,但它是第 3 方产品。)

我感谢任何人可以提供的任何见解。

4

2 回答 2

1

这里发生的是隐式转换。这意味着在 where 子句的条件中,您将列 INDEX3 与一个数字进行比较。

INDEX3 是一个 CHAR 列,因此 Oracle 文档的以下摘录适用于隐式转换:

在字符和非字符数据类型的算术运算和比较期间,Oracle 会根据需要从任何字符数据类型转换为数字、日期或 rowid

这意味着 INDEX3 中的所有值都将转换为 NUMBER,以便将它们与您在示例中给出的数字进行比较。

解决此问题的简单方法是在数字周围使用引号并将其视为字符串。

where INDEX3 = '524118914'

这将适用于相等条件,但对于使用 >= 和 <= 的范围可能效果不佳,除非它们在开头用零填充。使用正确的数据类型还意味着将使用此列上的任何索引。

如果您认为这应该是一个数字字段,那么至少有一行包含非数字数据。要追踪这一点,您可以尝试使用以下条件检查数据:

where regexp_like(INDEX3, '[^[:digit:]]')

这仅检查数字(不是小数点等),因此您可能需要根据您的要求对其进行调整。

我对为什么数据库说该列具有数字数据类型有点困惑。这似乎与评估 DECODE 语句的方式有关,并且数据类型来自第一个结果参数,即使默认参数是 CHAR 类型。

于 2012-05-16T19:26:14.397 回答
0

在字符字段中存储数字总是很痛苦......

请尝试以下 SQL 的视图 - 解码检查 PERSON_ID_CUSTOM 是否有数字。如果是,则转换它,如果不是 - 它将被 NULL 替换:

    SELECT UM00200M.ACCOUNT_NO AS INDEX1,
              CONCAT (CONCAT (TRIM (UM00200M.PERSON_LNM), ' '),
                      TRIM (UM00200M.PERSON_FNM))
                 AS INDEX2,
              DECODE (NVL (TRIM (SG00100M.PERSON_ID_CUSTOM), 0),
                      0, UM00200M.PERSON_NO,
decode((
  REPLACE(
   TRANSLATE(
    TRIM(SG00100M.PERSON_ID_CUSTOM),'0123456789','00000000000'
   ),'0' ,NULL
  )
 ),NULL,to_number(trim(SG00100M.PERSON_ID_CUSTOM)))
) INDEX3,
              NULL AS INDEX4,
              'CONS_ACCTG' AS GROUPNAME
         FROM UM00200M, SG00100M
        WHERE UM00200M.PERSON_NO = SG00100M.PERSON_NO
于 2012-05-16T19:16:37.800 回答