非常に大きなOracleテーブルで問題のあるレコードを見つけようとしています。列は、varchar2列であっても、すべての数値データを含む必要があります。数値データを含まないレコードを見つける必要があります(この列でto_number(col_name)関数を呼び出そうとすると、エラーがスローされます)。
Regexp_like条件を使用し、正規表現を使用して非数値を検索できると考えていました。これが役立つことを願っています!
SELECT * FROM table_with_column_to_search WHERE REGEXP_LIKE(varchar_col_with_non_numerics, '[^0-9]+');
インジケーターを取得するには:
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」のような数値以外の値がある場合、それは単に無視されます。
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のアプローチの場合、正の整数以外のものが必要な場合は、少し注意が必要です。
これを使って
SELECT *
FROM TableToSearch
WHERE NOT REGEXP_LIKE(ColumnToSearch, '^-?[0-9]+(\.[0-9]+)?$');
http://www.dba-Oracle.com/t_isnumeric.htm から
LENGTH(TRIM(TRANSLATE(, ' +-.0123456789', ' '))) is null
TRIMの後の文字列に何か残っている場合は、数字以外の文字である必要があります。
前の回答の提案に基づいていくつかのテストを行った後、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]+$');
この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;
私はこれが便利だと感じました:
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')
いくつかのテストを行った後、私はこの解決策を思いつきました。それが役立つ場合はお知らせください。
これをクエリの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