Comment puis-je déterminer si une chaîne de caractères est numérique en SQL?
dans une requête SQL sur Oracle 10g, je dois déterminer si une chaîne est numérique ou non. Comment puis-je faire cela?
7 réponses
vous pouvez utiliser REGEXP_LIKE:
SELECT 1 FROM DUAL
WHERE REGEXP_LIKE('23.9', '^\d+(\.\d+)?$', '')
you can try this:
SELECT LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' '))) FROM DUAL
où string1 est ce que vous évaluez. Il retournera nul si numérique. Regardez ici pour plus de précisions
Je n'ai pas accès à une instance 10G pour tester, mais cela fonctionne en 9i:
CREATE OR REPLACE FUNCTION is_numeric (p_val VARCHAR2) RETURN NUMBER IS v_val NUMBER; BEGIN BEGIN IF p_val IS NULL OR TRIM (p_val) = '' THEN RETURN 0; END IF; SELECT TO_NUMBER (p_val) INTO v_val FROM DUAL; RETURN 1; EXCEPTION WHEN OTHERS THEN RETURN 0; END; END; SELECT is_numeric ('333.5') is_numeric FROM DUAL;
j'ai supposé que vous vouliez que nulls/empties soit considéré comme faux.
comme le souligne Tom Kyte dans http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:7466996200346537833 , si vous utilisez le TO_NUMBER
intégré dans une fonction définie par l'utilisateur, vous pouvez avoir besoin d'un peu de ruse supplémentaire pour le faire fonctionner.
FUNCTION is_number(x IN VARCHAR2)
RETURN NUMBER
IS
PROCEDURE check_number (y IN NUMBER)
IS
BEGIN
NULL;
END;
BEGIN
PRAGMA INLINE(check_number, 'No');
check_number(TO_NUMBER(x);
RETURN 1;
EXCEPTION
WHEN INVALID_NUMBER
THEN RETURN 0;
END is_number;
le problème est que le compilateur d'optimisation mai reconnaître que le résultat du TO_NUMBER
n'est pas utilisé n'importe où et l'optimiser loin.
dit Tom (son exemple concernait les dates plutôt que les nombres):
la désactivation de la fonction inlining fera l'appel à check_date doit être fait comme une fonction l'appelant pour que le La DATE doit être placée sur la pile d'appels. Il n'y a aucune chance pour l' compilateur optimisant pour supprimer l'appel à to_date dans ce cas. Si l' l'appel à to_date nécessaire pour l'appel à check_date échoue raison, nous savons que la chaîne d'entrée n'était pas convertible à cette date format.
Voici une méthode pour déterminer numérique qui peut faire partie d'une requête simple, sans créer une fonction. Comptes pour des espaces, +- pas le premier caractère, ou un deuxième point décimal.
var v_test varchar2(20);
EXEC :v_test := ' -24.9 ';
select
(case when trim(:v_test) is null then 'N' ELSE -- only banks, or null
(case when instr(trim(:v_test),'+',2,1) > 0 then 'N' ELSE -- + sign not first char
(case when instr(trim(:v_test),'-',2,1) > 0 then 'N' ELSE -- - sign not first char
(case when instr(trim(:v_test),' ',1,1) > 0 then 'N' ELSE -- internal spaces
(case when instr(trim(:v_test),'.',1,2) > 0 then 'N' ELSE -- second decimal point
(case when LENGTH(TRIM(TRANSLATE(:v_test, ' +-.0123456789',' '))) is not null then 'N' ELSE -- only valid numeric charcters.
'Y'
END)END)END)END)END)END) as is_numeric
from dual;
j'ai trouvé que la solution
LENGTH(TRIM(TRANSLATE(string1, ' +-.0123456789', ' '))) is null
permet les blancs encastrés ... il accepte "123 45 6789" qui, pour moi, n'est pas un nombre.
un autre niveau de trim/translate corrige cela. Ce qui suit détectera un champ de chaîne de caractères contenant des chiffres consécutifs avec des blancs de début ou de fin tels que to_number(trim (string1)) ne échouera pas
LENGTH(TRIM(TRANSLATE(translate(trim(string1),' ','X'), '0123456789', ' '))) is null
pour les entiers, vous pouvez utiliser ce qui suit. La première translate change les espaces pour être un caractère et la seconde change les nombres pour être des espaces. Le Trim retournera alors null si seuls les nombres existent.
TRIM(TRANSLATE(TRANSLATE(TRIM('1 2 3d 4'), ' ','@'),'0123456789',' ')) is null