vérifier si la fonction" c'est un nombre " dans Oracle

j'essaie de vérifier si une valeur d'une colonne dans une requête oracle (10g) est un nombre afin de la comparer. Quelque chose comme:

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

des idées pour vérifier ça?

34
demandé sur Doug Porter 2011-02-22 21:22:43

15 réponses

en supposant que la colonne ID dans myTable n'est pas déclarée comme un nombre (ce qui semble être un choix étrange et susceptible d'être problématique), vous pouvez écrire une fonction qui essaie de convertir L'ID (probablement VARCHAR2) en un nombre, saisit l'exception et renvoie un 'Y' ou un 'N'. Quelque chose comme

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;

vous pouvez alors intégrer cet appel dans une requête, i.e.

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

notez que bien que PL / SQL ait un type de données booléen, SQL ne pas. Ainsi, alors que vous pouvez déclarer une fonction qui renvoie un booléen, vous ne pouvez pas utiliser cette fonction dans une requête SQL.

31
répondu Justin Cave 2014-04-24 17:32:01

Une autre idée, mentionnée ici est d'utiliser une expression régulière pour vérifier:

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

la partie agréable est que vous n'avez pas besoin d'une fonction PL/SQL séparée. Potentiellement problématiques partie est qu'une expression régulière peut ne pas être la méthode la plus efficace pour un grand nombre de lignes.

61
répondu Saish 2012-03-19 13:48:50

réponse de Saish en utilisant REGEXP_LIKE est la bonne idée, mais ne supporte pas les nombres flottants. Celui-ci sera ...

valeurs de retour numériques

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

valeurs de retour non numériques

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

vous pouvez tester vos expressions régulières eux-mêmes jusqu'à ce que votre cœur se contente de http://regexpal.com / (mais assurez-vous de cocher la case lors des sauts de ligne pour celui-ci).

14
répondu Matt Byrne 2014-01-20 04:54:20

vous pouvez utiliser la fonction d'expression régulière 'regexp_like' dans ORACLE (10g)comme suit:

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
répondu Kanu 2012-06-11 21:30:29

il s'agit d'un duplicata potentiel de lignes de recherche qui ne contiennent pas de données numériques dans Oracle . Voir aussi: Comment puis-je déterminer si une chaîne est numérique en SQL? .

Voici une solution basée sur de Michael Durrant qui fonctionne pour les entiers.

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

Adrian Carneiro a publié une solution qui fonctionne pour les décimales et autres. Cependant, comme Justin Cave a souligné, cela classera incorrectement les chaînes comme "123.45.23.234" ou "131+234".

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

si vous avez besoin d'une solution sans PL/SQL ou REGEXP_LIKE, cela peut vous aider.

5
répondu kevlened 2017-05-23 12:03:02

je suis contre l'utilisation de when others donc j'utiliserais (retourner un" entier booléen "en raison de SQL ne supporte pas les booléens)

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;

dans L'appel SQL vous utiliseriez quelque chose comme

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
répondu Filipe Silva 2011-02-23 02:37:41

comment la colonne est-elle définie? Si c'est un champ varchar, alors ce n'est pas un nombre (ou stocké comme un). Oracle peut être en mesure de faire la conversion pour vous (par exemple, select * de someTable où charField = 0), mais il ne retournera les lignes où la conversion est vraie et est possible. C'est aussi loin de la situation idéale de performance sage.

donc, si vous voulez faire des comparaisons de nombres et traiter cette colonne comme un nombre, peut-être qu'il devrait être défini comme un nombre?

cela dit, voici ce que vous pourriez faire:

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;

Vous pouvez également inclure les autres paramètres que le to_number. Utiliser comme suit:

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

il ne retournera aucune ligne que Oracle considère comme un nombre invalide.

santé.

1
répondu tbone 2011-02-22 19:16:53
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;

s'il vous plaît noter qu'il ne considérera pas 45e4 comme un nombre, mais vous pouvez toujours changer regex pour accomplir le contraire.

1
répondu Waqas Ashraf 2012-09-17 09:29:26

@JustinCave-le remplacement de" when value_error "Pour" when others " est un bon raffinement de votre approche ci-dessus. Cette légère modification supplémentaire, bien que conceptuellement la même, supprime l'exigence pour la définition de et l'allocation de mémoire conséquente à votre variable 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;

juste une note aussi à quiconque préférant émuler la logique de format de nombre Oracle en utilisant L'approche REGEXP "plus risquée", s'il vous plaît n'oubliez pas de considérer NLS_NUMERIC_CHARACTERS et NLS_TERRITORIUM.

1
répondu Pancho 2014-04-28 09:49:57

c'est ma requête pour trouver tous ceux qui ne sont pas numéro:

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

dans mon domaine . et, les nombres décimaux ont malheureusement dû tenir compte de cela, sinon vous n'avez besoin que d'une seule de la restriction.

1
répondu TheBakker 2016-01-22 14:26:44

Eh bien, vous pouvez créer la fonction is_number à appeler pour que votre code fonctionne.

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;

EDIT: reportez-vous à la réponse de Justin. J'ai oublié ce petit détail pour un appel SQL pur....

0
répondu Michael Broughton 2011-02-22 18:33:34

fonction pour numéro mobile de longueur 10 chiffres et à partir de 9,8,7 en utilisant regexp

create or replace FUNCTION VALIDATE_MOBILE_NUMBER
(   
   "MOBILE_NUMBER" IN varchar2
)
RETURN varchar2
IS
  v_result varchar2(10);

BEGIN
    CASE
    WHEN length(MOBILE_NUMBER) = 10 
    AND MOBILE_NUMBER IS NOT NULL
    AND REGEXP_LIKE(MOBILE_NUMBER, '^[0-9]+$')
    AND MOBILE_NUMBER Like '9%' OR MOBILE_NUMBER Like '8%' OR MOBILE_NUMBER Like '7%'
    then 
    v_result := 'valid';
    RETURN v_result;
      else 
      v_result := 'invalid';
       RETURN v_result;
       end case;
    END;
-1
répondu 2012-12-12 06:00:03

je crois que la solution suivante (basée sur l'approche regexp_like ci-dessus) est optimale:

function isInteger(vYourValue IN varchar2)
         return varchar2
         is
begin
  return case REGEXP_INSTR(vYourValue,'^[[:digit:]]+$') when 0 then 'F' else 'T' end;
end;

pourquoi je dis ça?

  1. le sous-ensemble numérique testé peut être modifié tel que désiré en changeant le regexp de façon appropriée.

  2. il peut être utilisé en SQL IE select isInteger(myCol) à partir de mytable; comme il retourne 'T' de 'F' au lieu de booléen.

  3. il peut être utilisé nativement en pl/sql ie. si isInteger (vMyValue) = 'T' alors ....

  4. il satisfait une assertion WNDS,wnps purity.

  5. il ne s'appuie pas, à mon avis, sur l'approche trop large "when others" pour la détermination des résultats.

-1
répondu Pancho 2014-04-23 22:12:51

Notez que regexp ou en fonction des approches sont plusieurs fois plus lent que la plaine sql condition .

ainsi quelques solutions heuristiques avec une applicabilité limitée font sence pour des scans énormes.

il y a une solution pour les cas où vous savez avec certitude que des valeurs non numériques contiendraient des lettres alphabétiques:

select case when upper(dummy)=lower(dummy) then '~numeric' else '~alpabetic' end from dual

Et si vous savez quelque lettre serait toujours présents dans les cas non numériques:

select case when instr(dummy, 'X')>0 then '~alpabetic' else '~numeric' end from dual

quand les cases numériques contiendraient toujours zéro:

select case when instr(dummy, '0')=0 then '~alpabetic' else '~numeric' end from dual
-1
répondu Vadzim 2017-05-23 12:10:11

si la condition est nulle, alors c'est le nombre

IF(rtrim(P_COD_LEGACY, '0123456789') IS NULL) THEN
                return 1;
          ELSE
                return 0;
          END IF;
-1
répondu Alejandro Soler 2015-12-21 20:28:03