Поиск строк, которые не содержат числовые данные в Oracle - PullRequest
16 голосов
/ 31 октября 2011

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

Ответы [ 9 ]

19 голосов
/ 31 октября 2011

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

SELECT * FROM table_with_column_to_search WHERE REGEXP_LIKE(varchar_col_with_non_numerics, '[^0-9]+');
11 голосов
/ 31 октября 2011

Чтобы получить показатель:

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

5 голосов
/ 11 ноября 2014

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

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

4 голосов
/ 05 мая 2017

Используйте это

SELECT * 
FROM TableToSearch 
WHERE NOT REGEXP_LIKE(ColumnToSearch, '^-?[0-9]+(\.[0-9]+)?$');
2 голосов
/ 29 сентября 2016

С http://www.dba -oracle.com / t_isnumeric.htm

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

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

0 голосов
/ 20 января 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
0 голосов
/ 03 мая 2016

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

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;
0 голосов
/ 19 января 2015

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

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

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

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

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

SELECT *
FROM <table>
WHERE NOT REGEXP_LIKE(<char_column>, '^[0-9]+$');
0 голосов
/ 12 июня 2012

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

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

Если результат равен NULL, он числовой (игнорируя числа с плавающей запятой.)

Однако, я немного озадачен, зачем подчеркивание. Без этого следующее также возвращает нуль:

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

Есть также один из моих любимых трюков - не идеален, если строка содержит такие вещи, как "*" или "#":

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