SELECT TO_NUMBER('*') FROM DUAL
Cela me donne évidemment une exception:
ORA-01722: numéro invalide
Existe-t-il un moyen de le "sauter" et d'obtenir 0
ou NULL
à la place?
Toute la question: j'ai NVARCHAR2
champ, qui contient des nombres et pas presque ;-) (comme *
) et je dois sélectionner le plus grand nombre dans la colonne.
Oui, je sais que c'est un design terrible, mais c'est ce dont j'ai besoin maintenant ...: -S
UPD :
Pour moi, j'ai résolu ce problème avec
COALESCE(TO_NUMBER(REGEXP_SUBSTR(field, '^\d+')), 0)
Je n'ai rien trouvé de mieux que ça:
function safe_to_number(p varchar2) return number is
v number;
begin
v := to_number(p);
return v;
exception when others then return 0;
end;
COALESCE(TO_NUMBER(REGEXP_SUBSTR(field, '^\d+(\.\d+)?')), 0)
obtiendra également des nombres avec une échelle> 0 (chiffres à droite de la virgule décimale).
De Oracle Database 12c Release 2
vous pouvez utiliser TO_NUMBER avec DEFAULT ... ON CONVERSION ERROR
:
SELECT TO_NUMBER('*' DEFAULT 0 ON CONVERSION ERROR) AS "Value"
FROM DUAL;
Ou CAST
:
SELECT CAST('*' AS NUMBER DEFAULT 0 ON CONVERSION ERROR) AS "Value"
FROM DUAL;
select COALESCE(TO_NUMBER(REGEXP_SUBSTR( field, '^(-|+)?\d+(\.|,)?(\d+)?$')), 0) from dual;
Il convertira 123 en 12, mais 123a ou 12a3 à .
S'adapter à la question d'origine et à une école plutôt ancienne
select a, decode(trim(translate(b,'0123456789.',' ')),null,to_number(b),0) from
(
select '1' a, 'not a number' b from dual
union
select '2' a, '1234' b from dual
)
Il est probablement un peu compliqué de lancer votre propre expression rationnelle pour tester un nombre, mais le code ci-dessous pourrait fonctionner. Je pense que l'autre solution de Gabe impliquant une fonction définie par l'utilisateur est plus robuste car vous utilisez la fonctionnalité Oracle intégrée (et mon expression rationnelle n'est probablement pas correcte à 100%) mais cela pourrait valoir la peine:
with my_sample_data as (
select '12345' as mynum from dual union all
select '54-3' as mynum from dual union all
select '123.4567' as mynum from dual union all
select '.34567' as mynum from dual union all
select '-0.3462' as mynum from dual union all
select '0.34.62' as mynum from dual union all
select '1243.64' as mynum from dual
)
select
mynum,
case when regexp_like(mynum, '^-?\d+(\.\d+)?$')
then to_number(mynum) end as is_num
from my_sample_data
Cela donnera alors la sortie suivante:
MYNUM IS_NUM
-------- ----------
12345 12345
54-3
123.4567 123.4567
.34567
-0.3462 -0.3462
0.34.62
1243.64 1243.64
select DECODE(trim(TRANSLATE(replace(replace(A, ' '), ',', '.'), '0123456789.-', ' ')),
null,
DECODE(INSTR(replace(replace(A, ' '), ',', '.'), '.', INSTR(replace(replace(A, ' '), ',', '.'), '.') + 1),
0,
DECODE(INSTR(replace(replace(A, ' '), ',', '.'), '-', 2),
0,
TO_NUMBER(replace(replace(A, ' '), ',', '.'))))) A
from (select '-1.1' A from DUAL union all select '-1-1' A from DUAL union all select ',1' A from DUAL union all select '1..1' A from DUAL) A;
Ce code exclut des chaînes telles que: -1-1, 1..1, 12-2 et ainsi de suite. Et je n'ai pas utilisé d'expressions régulières ici.
La meilleure méthode semble être la solution fonctionnelle, mais si vous ne disposez pas des privilèges nécessaires dans l'environnement que vous rencontrez (comme moi), vous pouvez essayer celle-ci:
SELECT
CASE
WHEN
INSTR(TRANSLATE('123O0',
' qwertyuıopğüasdfghjklşizxcvbnmöçQWERTYUIOPĞÜASDFGHJKLŞİZXCVBNMÖÇ~*\/(){}&%^#$<>;@€|:_=',
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
),
'X') > 0
THEN 'Y'
ELSE 'N'
END is_nonnumeric
FROM DUAL
Soit dit en passant: dans mon cas, le problème était dû à "," et "." :) Alors prenez cela en considération. Inspiré de celui-ci . Aussi celui-ci semble plus concis.
Au fait 2: Cher Oracle, pouvez-vous s'il vous plaît créer des fonctions intégrées pour des besoins aussi petits mais précieux?
Une combinaison de solutions précédentes (de @sOliver et @Mike Meyers) et en essayant d'attraper autant de numéros que possible en supprimant le dernier "$" de REGEXP.
Il peut être utilisé pour filtrer le nombre réel à partir d'une table de configuration et avoir un "genre" de commentaire à côté du nombre "12 jours".
with my_sample_data as ( select '12345' as mynum from dual union all select '123.4567' as mynum from dual union all select '-0.3462' as mynum from dual union all select '.34567' as mynum from dual union all select '-.1234' as mynum from dual union all select '**' as mynum from dual union all select '0.34.62' as mynum from dual union all select '24Days' as mynum from dual union all select '42ab' as mynum from dual union all select '54-3' as mynum from dual ) SELECT mynum, COALESCE( TO_NUMBER( REGEXP_SUBSTR( mynum, '^(-|+)?\d*(.|,)?(\d+)?') ) , 0) is_num FROM my_sample_data;
donnerait
MYNUM IS_NUM
-------- ----------
12345 12345
123.4567 123.4567
-0.3462 -0.3462
.34567 0.34567
-.1234 -0.1234
** 0
0.34.62 0.34
24Days 24
42ab 42
54-3 54