web-dev-qa-db-ja.com

Oracleで数値データを含まない行を見つける

非常に大きなOracleテーブルで問題のあるレコードを見つけようとしています。列は、varchar2列であっても、すべての数値データを含む必要があります。数値データを含まないレコードを見つける必要があります(この列でto_number(col_name)関数を呼び出そうとすると、エラーがスローされます)。

17
Ben

Regexp_like条件を使用し、正規表現を使用して非数値を検索できると考えていました。これが役立つことを願っています!

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

インジケーターを取得するには:

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」のような数値以外の値がある場合、それは単に無視されます。

12
Michael Durrant

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のアプローチの場合、正の整数以外のものが必要な場合は、少し注意が必要です。

5
ciuly

これを使って

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

http://www.dba-Oracle.com/t_isnumeric.htm から

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

TRIMの後の文字列に何か残っている場合は、数字以外の文字である必要があります。

2
capitano666

前の回答の提案に基づいていくつかのテストを行った後、2つの使用可能なソリューションがあるようです。

方法1は最速ですが、より複雑なパターンのマッチングに関してはそれほど強力ではありません。
方法2はより柔軟ですが、速度が遅くなります。

方法1-最速
100万行のテーブルでこのメソッドをテストしました。
正規表現ソリューションよりも3.8倍速いようです。
0置換は、0がスペースにマップされるという問題を解決し、クエリが遅くなることはないようです。

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

方法2-より遅いが、より柔軟
regexステートメントの内側または外側に否定を配置する速度を比較しました。どちらも、translate-solutionよりも同様に低速です。その結果、@ ciulyのアプローチは、正規表現を使用する場合に最も賢明です。

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

この1つのチェックを使用できます。

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
egor7

私はこれが便利だと感じました:

 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')
0
aiGuru

いくつかのテストを行った後、私はこの解決策を思いつきました。それが役立つ場合はお知らせください。

これをクエリの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
JAY SOPARIYA