【问题标题】:Prevent ORA-01722: invalid number in Oracle防止 ORA-01722:Oracle 中的数字无效
【发布时间】:2018-06-25 08:04:59
【问题描述】:

我有这个问题

  SELECT text
         FROM book
              WHERE lyrics IS NULL
            AND MOD(TO_NUMBER(SUBSTR(text,18,16)),5) = 1

有时字符串类似于$OK$OK$OK$OK$OK$OK$OK,有时类似于@P,351811040302663;E,101;D,07112018134733,07012018144712;G,4908611,50930248,207,990;M,79379;S,0;IO,3,0,0

如果我想知道是否可以防止 ORA-01722: invalid number,因为某些原因导致该位置的字符不是数字。 我在一个过程中运行此查询,处理游标中的所有行,如果 1 行不是数字,我无法处理任何行

【问题讨论】:

  • 为什么将重要的数字存储为字符串的一部分?
  • 请显示示例字符串
  • 查看引用帖子中的所有答案。
  • @jarlh - 有时这不是发布者(甚至整个数据库行业)的选择(错误)。以 VIN(车辆识别号)为例。一张表可以存储汽车租赁业务中汽车的 VIN。这是一个长的单字符串。它的不同部分(一些字母字符,一些数字)编码不同的东西。 DB 必须存储 VIN。即使想要提取不同的位并将它们分开存储,他们仍然需要像 OP 那样做一些事情。对吗?
  • @timbiegeleisen - 对于那些以完全重复的方式结束问题的人:不是。您指出的问题询问如何找到非数字的值。在这个线程中,OP 询问如何防止 ORA-01722。这是一个不同的问题,即使它们是相关的。如果您想将其作为重复项关闭,请找到一个确切的。

标签: sql oracle oracle12c


【解决方案1】:
        SELECT text
     FROM book
          WHERE lyrics IS NULL
        AND case when regexp_like(SUBSTR(text,18,16),'^[^a-zA-Z]*$') then MOD(TO_NUMBER(SUBSTR(text,18,16)),5)
            else null 
            end = 1;

【讨论】:

  • 问题中的 OP 已经在输入字符串中显示了非字母、非数字字符,因此仅检查字母是不够的。另外,在then 子句中,text( ..... ) 是什么意思?没有这样的功能。
【解决方案2】:

假设条件为真当且仅当从位置 18 开始的 16 个字符的子字符串由 16 位数字组成,并且该数字等于 1 模 5,那么您可以这样写:

...
where .....
  and case when translate(substr(text, 18, 16), 'z0123456789', 'z') is null
                and substr(text, 33, 1) in ('1', '6')
           then 1 end
      = 1

这将检查子字符串是否由全数字组成:translate() 函数会将字符串中出现的每个 z 替换为自身,并将每个出现的 0、1、...、9 替换为 nothing(它只会删除它们)。由于 Oracle 对 NULL 和空字符串的奇怪实现,需要看起来很奇怪的 z(您可以使用任何其他字符代替 z,但您需要 some 字符,因此translate() 的参数没有为 NULL) .然后 - 当且仅当此转换的结果为空(空字符串)时,子字符串由所有数字组成。你仍然检查最后一个字符是 1 还是 6。

请注意,我没有使用任何正则表达式;如果您有大量数据,这一点很重要,因为像 translate() 这样的标准字符串函数比正则表达式函数快得多。此外,一切都基于字符数据类型 - 没有像 mod() 这样的数学函数。 (与 Thorsten 的回答相同,只是缺少我在这里建议的第一部分 - 检查整个子字符串是否由数字组成。)

【讨论】:

    【解决方案3】:

    如果是 Oracle 12c 第 2 版 (12.2),您可以使用 VALIDATE_CONVERSION

    WITH book(text) AS
      (SELECT '@P,351811040302663;E,101;D,07112018134733,07012018144712;G,4908611,50930248,207,990;M,79379;S,0;IO,3,0,0'
       FROM DUAL
       UNION ALL SELECT '$OK$OK$OK$OK$OK$OK$OK'
       FROM DUAL
       UNION ALL SELECT '12I45678912B456781234567812345671'
       FROM DUAL)
    SELECT *
    FROM book
    WHERE CASE
              WHEN VALIDATE_CONVERSION(SUBSTR(text,18,16) AS NUMBER) = 1 
               THEN MOD(TO_NUMBER(SUBSTR(text,18,16)),5)
              ELSE 0
          END = 1 ;
    

    输出

    TEXT
    12I45678912B456781234567812345671
    

    【讨论】:

    • 可以使用不同的 12.2 功能简化谓词:mod(to_number(SUBSTR(text,18,16) default 0 on conversion error),5) = 1
    猜你喜欢
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    相关资源
    最近更新 更多