web-dev-qa-db-ja.com

Oracleで「それが数字だ」関数かどうかを確認します

比較するために、Oracle(10g)クエリの列の値が数値であるかどうかを確認しようとしています。何かのようなもの:

select case when ( is_number(myTable.id) and (myTable.id >0) ) 
            then 'Is a number greater than 0' 
            else 'it is not a number' 
       end as valuetype  
  from table myTable

それを確認する方法についてのアイデアはありますか?

35
Fgblanch

myTableのID列がNUMBERとして宣言されていないと仮定すると(これは奇妙な選択であり、問​​題があると思われます)、(おそらくVARCHAR2)IDを数値に変換しようとする関数を記述できます、例外をキャッチし、「Y」または「N」を返します。何かのようなもの

CREATE OR REPLACE FUNCTION is_number( p_str IN VARCHAR2 )
  RETURN VARCHAR2 DETERMINISTIC PARALLEL_ENABLE
IS
  l_num NUMBER;
BEGIN
  l_num := to_number( p_str );
  RETURN 'Y';
EXCEPTION
  WHEN value_error THEN
    RETURN 'N';
END is_number;

その後、その呼び出しをクエリに埋め込むことができます。

SELECT (CASE WHEN is_number( myTable.id ) = 'Y' AND myTable.id > 0 
               THEN 'Number > 0'
             ELSE 'Something else'
         END) some_alias
  FROM myTable

PL/SQLにはブールデータ型がありますが、SQLにはないことに注意してください。したがって、ブール値を返す関数を宣言することはできますが、SQLクエリでそのような関数を使用することはできません。

32
Justin Cave

here に言及したもう1つのアイデアは、正規表現を使用して確認することです。

SELECT  foo 
FROM    bar
WHERE   REGEXP_LIKE (foo,'^[[:digit:]]+$');

良い点は、別のPL/SQL関数が必要ないことです。問題となる可能性のある部分は、正規表現が多数の行に対して最も効率的な方法ではない可能性があることです。

61
Saish

REGEXP_LIKEを使用したSaishの答えは正しい考えですが、浮動小数点数はサポートしていません。これは...

数値の戻り値

SELECT  foo 
FROM    bar
WHERE   REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');

数値ではない戻り値

SELECT  foo 
FROM    bar
WHERE   NOT REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');

http://regexpal.com/ (ただし、改行で一致するチェックボックスを選択してくださいこのため。

15
Matt Byrne

これは、 Oracleに数値データを含まない行を見つける の潜在的な重複です。次も参照してください: SQLで文字列が数値であるかどうかを確認する方法は? .

Michael Durrant's に基づく解決策は、整数に対して機能します。

SELECT foo
FROM bar
WHERE DECODE(TRIM(TRANSLATE(your_number,'0123456789',' ')), NULL, 'number','contains char') = 'number'

Adrian Carneiro 小数などで機能するソリューションを投稿しました。ただし、Justin Caveが指摘したように、これにより「123.45.23.234」や「131 + 234」などの文字列が誤って分類されます。

SELECT foo
FROM bar
WHERE DECODE(TRIM(TRANSLATE(your_number,'+-.0123456789',' ')), NULL, 'number','contains char') = 'number'

PL/SQLまたはREGEXP_LIKEを使用しないソリューションが必要な場合、これが役立つ場合があります。

5
kevlened

次のように、Oracle(10g)で正規表現関数「regexp_like」を使用できます。

select case
       when regexp_like(myTable.id, '[[:digit:]]') then
        case
       when myTable.id > 0 then
        'Is a number greater than 0'
       else
        'Is a number less than or equal to 0'
     end else 'it is not a number' end as valuetype
from table myTable
5
Kanu

私はwhen othersを使用することに反対ですので、使用します(SQLがブール値をサポートしていないため「ブール整数」を返します)

create or replace function is_number(param in varchar2) return integer
 is
   ret number;
 begin
    ret := to_number(param);
    return 1; --true
 exception
    when invalid_number then return 0;
 end;

SQL呼び出しでは、次のようなものを使用します

select case when ( is_number(myTable.id)=1 and (myTable.id >'0') ) 
            then 'Is a number greater than 0' 
            else 'it is not a number or is not greater than 0' 
       end as valuetype  
  from table myTable
2
Filipe Silva
CREATE OR REPLACE FUNCTION is_number(N IN VARCHAR2) RETURN NUMBER IS
  BEGIN
    RETURN CASE regexp_like(N,'^[\+\-]?[0-9]*\.?[0-9]+$') WHEN TRUE THEN 1 ELSE 0 END;
END is_number;

45e4は数字とは見なされないことに注意してください。しかし、正規表現をいつでも変更して反対のことを達成できます。

1
Waqas Ashraf

これは、番号ではないすべてのものを見つけるための私のクエリです:

Select myVarcharField
From myTable
where not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\.\d+)?$', '')
and not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\,\d+)?$', '');

私の分野で私はしました。そして、悲しいことに、10進数はそれを考慮に入れなければなりませんでした。

1
TheBakker

列はどのように定義されていますか? varcharフィールドの場合、数値ではありません(または1として格納されます)。 Oracleは変換を実行できる場合があります(たとえば、charField = 0のsomeTableから*を選択します)が、変換が成立し、可能な場合にのみ行を返します。これは、理想的なパフォーマンスとはほど遠いです。

したがって、数値比較を行い、この列を数値として扱いたい場合、おそらく数値として定義する必要がありますか?

とはいえ、ここであなたができることは次のとおりです。

create or replace function myToNumber(i_val in varchar2) return number is
 v_num number;
begin
 begin
   select to_number(i_val) into v_num from dual;
 exception
   when invalid_number then
   return null;
 end;
 return v_num;
end;

通常のto_numberにある他のパラメーターも含めることができます。そのまま使用:

select * from someTable where myToNumber(someCharField) > 0;

Oracleが無効な数値と見なす行は返されません。

乾杯。

1
tbone

@JustinCave-「when other」の「when value_error」の置き換えは、上記のアプローチに対する素晴らしい改良です。このわずかな追加のTweakは、概念的には同じですが、l_num変数の定義とその結果のメモリ割り当ての要件を削除します。

function validNumber(vSomeValue IN varchar2)
     return varchar2 DETERMINISTIC PARALLEL_ENABLE
     is
begin
  return case when abs(vSomeValue) >= 0 then 'T' end;
exception
  when value_error then
    return 'F';
end;

「riskier」REGEXPアプローチを使用してOracleの数値形式ロジックをエミュレートすることを好む人にも注意してください。NLS_NUMERIC_CHARACTERSとNLS_TERRITORYを考慮することを忘れないでください。

1
Pancho

まあ、is_number関数を作成して呼び出すと、コードが機能します。

create or replace function is_number(param varchar2) return boolean
 as
   ret number;
 begin
    ret := to_number(param);
    return true;
 exception
    when others then return false;
 end;

編集:ジャスティンの答えに従ってください。純粋なSQL呼び出しの詳細を忘れていました。

0

この例を使用できます

SELECT NVL((SELECT 1 FROM  DUAL WHERE   REGEXP_LIKE (:VALOR,'^[[:digit:]]+$')),0) FROM DUAL;
0
Omar Medrano