Поиск строк, не содержащих числовых данных в Oracle

Я пытаюсь найти проблемные записи в очень большой таблице Oracle. Столбец должен содержать все числовые данные, даже если это столбец varchar2. Мне нужно найти записи, которые не содержат числовых данных (функция to_number(col_name) выдает ошибку, когда я пытаюсь вызвать ее в этом столбце).


person Ben    schedule 31.10.2011    source источник


Ответы (10)


Я подумал, что вы могли бы использовать условие regexp_like и использовать регулярное выражение для поиска любых нечисловых значений. Я надеюсь, что это может помочь?!

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

Чтобы получить индикатор:

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

e.g.

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», оно будет просто проигнорировано.

person Michael Durrant    schedule 31.10.2011
comment
Майкл, есть небольшая проблема с вашим переводом, если строка, которую вы проверяете, содержит ноль. TRANSLATE превратит любые нули в пробелы. Например: выберите DECODE( TRANSLATE('123405','0123456789',' '), NULL, 'число','содержит char') из двойного возврата, содержит char - person aiGuru; 12.06.2012
comment
Я полагаю, что и в 10g он есть :) cd/B12037_01/server.101/b10759/ - person Bill Ortell; 07.08.2013
comment
@aiGuru Я исправил эту проблему, добавив начальный пробел ко второму параметру TRANSLATE. Проблема в том, что TRANSLATE считал ноль совпадением, потому что это был первый символ. - person GreenGiant; 16.11.2017

В отличие от ответа SGB, я предпочитаю регулярное выражение, определяющее фактический формат моих данных и отрицающее это. Это позволяет мне определять такие значения, как $DDD,DDD,DDD.DD. В простом сценарии OP это будет выглядеть так:

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 было бы немного сложно сделать, если вам нужно больше, чем просто положительные целые числа.

person ciuly    schedule 11.11.2014

Использовать это

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

Проведя некоторое тестирование, я придумал это решение, дайте мне знать, если оно поможет.

Добавьте это ниже 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
person JAY SOPARIYA    schedule 20.01.2017

Из http://www.dba-oracle.com/t_isnumeric.htm

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

Если после TRIM в строке осталось что-то, это должны быть нечисловые символы.

person capitano666    schedule 29.09.2016
comment
Это может исключить нечисловые значения, такие как даты в формате ГГГГ-ММ-ДД, например. - person emi-le; 15.05.2019
comment
Числа — это не просто последовательности из приведенного выше списка. У них есть формат. 61..01 будет проверяться как числовое с использованием этого метода, даже если это не число. - person John Vance; 03.06.2020

Я нашел это полезным:

 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')
person aiGuru    schedule 12.06.2012
comment
Трюк с подчеркиванием работает только в том случае, если ваши данные никогда не содержат подчеркивания. Потому что translate сопоставляет символ подчеркивания с символом подчеркивания, а все остальные числа сопоставляет NULL. На самом деле это будет работать достаточно надежно, если вы используете символ, который вряд ли появится в ваших данных. - person Wouter; 19.01.2015
comment
Как уже упоминалось в моем собственном ответе, это полностью решает: TRANSLATE(replace(‹char_column›,'0',''),'0123456789',' ') и не влияет на скорость - person Wouter; 19.01.2015

После некоторого тестирования, основанного на предложениях в предыдущих ответах, кажется, есть два полезных решения.

Метод 1 самый быстрый, но менее мощный с точки зрения сопоставления более сложных шаблонов.
Метод 2 более гибкий, но медленный.

Метод 1 — самый быстрый
Я протестировал этот метод на таблице с 1 миллионом строк.
Похоже, что он в 3,8 раза быстрее, чем решения с регулярными выражениями.
Замена 0 решает проблему, связанную с тем, что 0 сопоставляется с пробелом, и, похоже, не замедляет выполнение запроса.

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

Способ 2 — более медленный, но более гибкий
Я сравнил скорость помещения отрицания внутри и снаружи оператора регулярного выражения. Оба одинаково медленнее, чем translate-solution. В результате подход @ciuly кажется наиболее разумным при использовании регулярных выражений.

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

Вы можете использовать эту проверку:

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;
person egor7    schedule 03.05.2016

введите здесь описание изображенияЯ упорядочиваю лотки по проблемному столбцу и нахожу строки с этим столбцом.

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
person Vitalie    schedule 02.02.2021