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 sur la façon de vérifier cela?
En supposant que la colonne ID dans myTable
ne soit pas déclarée comme NUMBER (ce qui semble être un choix étrange et susceptible de poser problème), vous pouvez écrire une fonction qui tente de convertir l'ID (probablement VARCHAR2) en un nombre , intercepte 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 ensuite intégrer cet appel à une requête, c'est-à-dire.
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 n'en a pas. Ainsi, bien que vous puissiez déclarer une fonction qui retourne un booléen, vous ne pouvez pas utiliser une telle fonction dans une requête SQL.
Une autre idée mentionnée ici consiste à utiliser une expression régulière pour vérifier:
SELECT foo
FROM bar
WHERE REGEXP_LIKE (foo,'^[[:digit:]]+$');
La partie intéressante est que vous n’avez pas besoin d’une fonction PL/SQL distincte. La partie potentiellement problématique est qu'une expression régulière peut ne pas être la méthode la plus efficace pour un grand nombre de lignes.
La réponse de Saish en utilisant REGEXP_LIKE
est la bonne idée mais ne supporte pas les nombres flottants. Celui-ci sera ...
Renvoie des valeurs numériques
SELECT foo
FROM bar
WHERE REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');
Renvoie des valeurs non numériques
SELECT foo
FROM bar
WHERE NOT REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');
Vous pouvez tester vos expressions régulières elles-mêmes jusqu'à ce que votre cœur soit content à http://regexpal.com/ (mais assurez-vous de cocher la case correspondante aux sauts de ligne pour celui-ci).
Il s'agit d'un doublon potentiel de Recherche de lignes 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 Michael Durrant's 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 nombres décimaux et autres. Cependant, comme l'a souligné Justin Cave, cela classera incorrectement des chaînes telles que '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 aider.
Vous pouvez utiliser la fonction d'expression régulière 'regexp_like' dans Oracle (10g) comme ci-dessous:
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
Je suis contre utiliser when others
donc je l’utiliserais (retourne un "entier booléen" car 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
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;
Veuillez noter que 45e4 ne sera pas considéré comme un nombre, mais vous pouvez toujours changer de regex pour accomplir le contraire.
Voici ma requête pour trouver tous ceux qui ne sont PAS numérotés:
Select myVarcharField
From myTable
where not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\.\d+)?$', '')
and not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\,\d+)?$', '');
Dans mon domaine j'ai. et, malheureusement, les nombres décimaux ont dû en tenir compte, sinon vous n’avez besoin que de l’une des restrictions.
Comment est définie la colonne? Si c'est un champ varchar, alors ce n'est pas un nombre (ou stocké en tant que tel). Oracle pourra peut-être effectuer la conversion pour vous (par exemple, sélectionnez * depuis une table où charField = 0), mais il ne renverra que les lignes dans lesquelles la conversion est vraie et possible. C’est aussi loin de la situation idéale en termes de performances.
Donc, si vous voulez faire des comparaisons de nombres et traiter cette colonne comme un nombre, peut-être devrait-elle être définie 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 du numéro to_number habituel. Utilisez comme tel:
select * from someTable where myToNumber(someCharField) > 0;
Il ne renverra aucune ligne considérée par Oracle comme un nombre non valide.
À votre santé.
@JustinCave - Le remplacement de "when" par "quand les autres" est un raffinement de votre approche ci-dessus. Ce léger tweak supplémentaire, bien que conceptuellement identique, supprime la nécessité de définir et d’allouer de la mémoire à 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 également pour tous ceux qui préfèrent émuler la logique de format de nombre Oracle en utilisant l’approche REGEXP "plus risquée", n’oubliez pas de prendre en compte NLS_NUMERIC_CHARACTERS et NLS_TERRITORY.
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: S'il vous plaît reporter à la réponse de Justin. J'ai oublié ce petit détail pour un appel SQL pur ....
Vous pouvez utiliser cet exemple
SELECT NVL((SELECT 1 FROM DUAL WHERE REGEXP_LIKE (:VALOR,'^[[:digit:]]+$')),0) FROM DUAL;