【问题标题】:Finding rows that don't contain numeric data in Oracle在 Oracle 中查找不包含数字数据的行
【发布时间】:2011-12-18 22:27:45
【问题描述】:

我试图在一个非常大的 Oracle 表中找到一些有问题的记录。该列应包含所有数字数据,即使它是 varchar2 列。我需要查找不包含数字数据的记录(当我尝试在此列上调用 to_number(col_name) 函数时会引发错误)。

【问题讨论】:

    标签: sql oracle varchar numeric varchar2


    【解决方案1】:

    获取指标:

    DECODE( TRANSLATE(your_number,' 0123456789',' ')
    

    例如

    SQL> select DECODE( TRANSLATE('12345zzz_not_numberee',' 0123456789',' '), NULL, 'number','contains char')
     2 from dual
     3 /
    
    "contains char"
    

    SQL> select DECODE( TRANSLATE('12345',' 0123456789',' '), NULL, 'number','contains char')
     2 from dual
     3 /
    
    "number"
    

    SQL> select DECODE( TRANSLATE('123405',' 0123456789',' '), NULL, 'number','contains char')
     2 from dual
     3 /
    
    "number"
    

    Oracle 11g 具有正则表达式,因此您可以使用它来获取实际数字

    SQL> SELECT colA
      2  FROM t1
      3  WHERE REGEXP_LIKE(colA, '[[:digit:]]');
    
    COL1
    ----------
    47845
    48543
    12
    ...
    

    如果有像“23g”这样的非数字值,它将被忽略。

    【讨论】:

    • Michael,如果您检查的字符串包含零,则您的翻译会出现小问题。 TRANSLATE 会将任何零转换为空格。例如:select DECODE( TRANSLATE('123405','0123456789',' '), NULL, 'number','contains char') from dual 返回“contains char”
    • @aiGuru 我通过在 TRANSLATE 的第二个参数中添加前导空格来解决这个问题。问题是 TRANSLATE 认为零是匹配的,因为它是第一个字符。
    【解决方案2】:

    我在想你可以使用 regexp_like 条件并使用正则表达式来查找任何非数字。我希望这可能会有所帮助?!

    SELECT * FROM table_with_column_to_search WHERE REGEXP_LIKE(varchar_col_with_non_numerics, '[^0-9]+');
    

    【讨论】:

      【解决方案3】:

      我发现这很有用:

       select translate('your string','_0123456789','_') from dual
      

      如果结果为 NULL,则为数字(忽略浮点数。)

      但是,我有点困惑为什么需要下划线。没有它,以下内容也返回 null:

       select translate('s123','0123456789', '') from dual
      

      还有一个我最喜欢的技巧 - 如果字符串包含诸如“*”或“#”之类的东西,那就不完美了:

       SELECT 'is a number' FROM dual WHERE UPPER('123') = LOWER('123')
      

      【讨论】:

      • “下划线技巧”仅在您的数据不包含下划线时才有效。因为 translate 将下划线映射到下划线,并将所有其他数字映射到 NULL。如果您使用最不可能出现在数据中的字符,这实际上会非常可靠地工作。
      • 正如我自己的回答中提到的,这完全解决了它: TRANSLATE(replace(,'0',''),'0123456789',' ') 并且没有速度影响
      【解决方案4】:

      与 SGB 的答案相比,我更喜欢使用正则表达式来定义我的数据的实际格式并否定它。这允许我定义像 $DDD,DDD,DDD.DD 这样的值 在 OPs 简单场景中,它看起来像

      SELECT * 
      FROM table_with_column_to_search 
      WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^[0-9]+$');
      

      查找所有非正整数。如果您也接受负整数,这是一个简单的更改,只需添加一个可选的前导减号。

      SELECT * 
      FROM table_with_column_to_search 
      WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+$');
      

      接受浮点数...

      SELECT * 
      FROM table_with_column_to_search 
      WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+(\.[0-9]+)?$');
      

      同样适用于任何格式。基本上,您通常已经拥有验证输入数据的格式,因此当您希望找到与该格式不匹配的数据时……否定该格式比提出另一种格式更简单;如果您想要的不仅仅是正整数,那么在 SGB 的方法中,这会有点棘手。

      【讨论】:

        【解决方案5】:

        在进行了一些测试后,根据之前答案中的建议,似乎有两个可用的解决方案。

        方法 1 最快,但在匹配更复杂的模式方面功能较弱。
        方法 2 更灵活,但速度较慢。

        方法 1 - 最快
        我已经在一个有 100 万行的表上测试了这种方法。
        它似乎比正则表达式解决方案快 3.8 倍。
        0 替换解决了 0 映射到空格的问题,并且似乎不会减慢查询速度。

        SELECT *
        FROM <table>
        WHERE TRANSLATE(replace(<char_column>,'0',''),'0123456789',' ') IS NOT NULL;
        

        方法 2 - 速度较慢,但​​更灵活
        我比较了将否定置于正则表达式语句内部或外部的速度。两者都比翻译解决方案慢。因此,@ciuly 的方法在使用正则表达式时似乎是最明智的。

        SELECT *
        FROM <table>
        WHERE NOT REGEXP_LIKE(<char_column>, '^[0-9]+$');
        

        【讨论】:

          【解决方案6】:

          您可以使用这一项检查:

          create or replace function to_n(c varchar2) return number is
          begin return to_number(c);
          exception when others then return -123456;
          end;
          
          select id, n from t where to_n(n) = -123456;
          

          【讨论】:

            【解决方案7】:

            来自http://www.dba-oracle.com/t_isnumeric.htm

            LENGTH(TRIM(TRANSLATE(, ' +-.0123456789', ' '))) is null
            

            如果在 TRIM 之后的字符串中还有任何内容,则它必须是非数字字符。

            【讨论】:

            • 这可以排除非数字值,例如格式为“YYYY-MM-DD”的日期。
            • 数字不仅仅是上述列表的序列。他们有一个格式。 61..01 将使用此方法测试为数字,即使它不是数字。
            【解决方案8】:

            在做了一些测试后,我想出了这个解决方案,如果有帮助,请告诉我。

            在您的查询中添加以下 2 个条件,它将找到不包含数字数据的记录

             and REGEXP_LIKE(<column_name>, '\D') -- this selects non numeric data
             and not REGEXP_LIKE(column_name,'^[-]{1}\d{1}') -- this filters out negative(-) values
            

            【讨论】:

              【解决方案9】:

              使用这个

              SELECT * 
              FROM TableToSearch 
              WHERE NOT REGEXP_LIKE(ColumnToSearch, '^-?[0-9]+(\.[0-9]+)?$');
              

              【讨论】:

                【解决方案10】:

                I 托盘排序有问题的列,我找到有列的行。

                SELECT 
                 D.UNIT_CODE,
                         D.CUATM,
                         D.CAPITOL,
                          D.RIND,
                          D.COL1  AS COL1
                
                
                FROM
                  VW_DATA_ALL_GC  D
                  
                  WHERE
                  
                   (D.PERIOADA IN (:pPERIOADA))  AND   
                   (D.FORM = 62) 
                   AND D.COL1 IS NOT NULL
                 --  AND REGEXP_LIKE (D.COL1, '\[\[:alpha:\]\]')
                 
                -- AND REGEXP_LIKE(D.COL1, '\[\[:digit:\]\]')
                 
                 --AND REGEXP_LIKE(TO_CHAR(D.COL1), '\[^0-9\]+')
                 
                 
                   GROUP BY 
                    D.UNIT_CODE,
                         D.CUATM,
                         D.CAPITOL,
                          D.RIND ,
                          D.COL1  
                         
                         
                        ORDER BY 
                        D.COL1
                

                【讨论】:

                  猜你喜欢
                  • 2023-04-10
                  • 2016-12-11
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-08-12
                  相关资源
                  最近更新 更多