Détecter si la valeur est un nombre dans MySQL

159

Existe-t-il un moyen de détecter si une valeur est un nombre dans une requête MySQL? Tel que

SELECT * 
FROM myTable 
WHERE isANumber(col1) = true
Urbycoz
la source
J'ai testé la stratégie 1 * col = col, mais elle échoue d'une manière ou d'une autre lorsque la requête est appelée via PHP (retournant true alors que cela ne devrait pas). Dans phpMyAdmin cependant, le hack fonctionne. Cela signifie que mon test se comporte comme prévu, mais pas l'achat de mon application.
Jahaziel

Réponses:

251

Cela devrait fonctionner dans la plupart des cas.

SELECT * FROM myTable WHERE concat('',col1 * 1) = col1

Cela ne fonctionne pas pour les nombres non standard comme

  • 1e4
  • 1.2e5
  • 123. (décimal de fin)
RichardTheKiwi
la source
Je vous remercie. Malheureusement, j'en ai besoin pour reconnaître que 123 est un nombre, mais 123X ne l'est pas.
Urbycoz
1
@ Richard- Je viens de lire les exceptions que vous avez données. Je pensais que vous vouliez dire le caractère "e". Je vois ce que tu veux dire maintenant.
Urbycoz
Les zéros non
significatifs
Je sais que c'est un ancien message mais j'utilise cette méthode dans ma requête. Mais j'ai un problème, il détecte "2-Power" comme "2" causant des problèmes car il n'est pas censé le faire. Une idée ?
GRosay
1
Pour les zéros de fin et de tête (ex. 023.12000): concat ('', col1 * 1) = '0' OR concat ('', col1 * 1) = IF (LOCATE ('.', Col1), TRIM (BOTH ' 0 'FROM col1), TRIM (DIRIGEANT' 0 'DE col1));
François Breton
299

Vous pouvez également utiliser l'expression régulière ... ce serait comme:

SELECT * FROM myTable WHERE col1 REGEXP '^[0-9]+$';

Référence: http://dev.mysql.com/doc/refman/5.1/en/regexp.html

T. Corner
la source
70
SELECT * FROM maTable WHERE col1 REGEXP '^ [0-9] + $';
Dmitriy Kozmenko
7
La réponse acceptée est vraiment intelligente, mais cette réponse est plus directe, et je pense que cela devrait être la solution acceptée.
pedromanoel
21
Pour le cas de «ne correspond pas»:, WHERE col1 NOT REGEXP...et pour le cas où vous pourriez avoir une virgule décimale, utilisez l'expression régulière:^[0-9\.]+$
Robbie Averill
2
Ne fonctionnera pas non plus pour la notation scientifique, ne fonctionne que pour les ints
David Wilkins
1
Regex migth être difficile à lire pour les personnes qui ne l'ont jamais utilisé, mais vous pouvez faire de très bonnes choses avec elle
Olli
56

Si vos données sont "test", "test0", "test1111", "111test", "111"

Pour sélectionner tous les enregistrements où les données sont un simple int:

SELECT * 
FROM myTable 
WHERE col1 REGEXP '^[0-9]+$';

Résultat: '111'

(Dans regex, ^ signifie début et $ signifie fin)

Pour sélectionner tous les enregistrements contenant un nombre entier ou décimal:

SELECT * 
FROM myTable 
WHERE col1 REGEXP '^[0-9]+\\.?[0-9]*$'; - for 123.12

Résultat: '111' (identique au dernier exemple)

Enfin, pour sélectionner tous les enregistrements où le nombre existe, utilisez ceci:

SELECT * 
FROM myTable 
WHERE col1 REGEXP '[0-9]+';

Résultat: 'test0' et 'test1111' et '111test' et '111'

Dmitriy Kozmenko
la source
J'aime mieux cette approche car elle est plus claire et moins «hackish» que l'astuce de concaténation. Merci!
brokethebuildagain
8
Ne fonctionne pas pour les valeurs négatives. Je modifierais l'expression rationnelle proposée comme suit:REGEXP '^[+\-]?[0-9]+\\.?[0-9]*$'
Nicolas
Je dirais que le symbole "+" n'est pas nécessaire, vous pouvez utiliser juste un "-?", Mais si vous voulez l'utiliser, vous devez l'échapper (et le symbole "-" n'a pas besoin d'être échappé) .
T. angle
13
SELECT * FROM myTable
WHERE col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$'

Correspondra également aux décimales signées (comme -1,2, +0,2, 6., 2e9, 1,2e-10 ).

Tester:

drop table if exists myTable;
create table myTable (col1 varchar(50));
insert into myTable (col1) 
  values ('00.00'),('+1'),('.123'),('-.23e4'),('12.e-5'),('3.5e+6'),('a'),('e6'),('+e0');

select 
  col1,
  col1 + 0 as casted,
  col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$' as isNumeric
from myTable;

Résultat:

col1   |  casted | isNumeric
-------|---------|----------
00.00  |       0 |         1
+1     |       1 |         1
.123   |   0.123 |         1
-.23e4 |   -2300 |         1
12.e-5 | 0.00012 |         1
3.5e+6 | 3500000 |         1
a      |       0 |         0
e6     |       0 |         0
+e0    |       0 |         0

Démo

Paul Spiegel
la source
3
Parfait! Seule réponse qui couvre en fait toutes les bases. Devrait être la réponse acceptée.
Dom
10

Renvoie des lignes numériques

J'ai trouvé la solution avec la requête suivante et fonctionne pour moi:

SELECT * FROM myTable WHERE col1 > 0;

Cette requête renvoie des lignes ayant uniquement une colonne numérique supérieure à zéro col1

Renvoie des lignes non numériques

si vous voulez vérifier la colonne non numérique, essayez celle-ci avec l'astuce ( !col1 > 0):

SELECT * FROM myTable WHERE !col1 > 0;
Bora
la source
Cela ne fonctionne pas, si vous avez une chaîne qui commence par un nombre "123abc", elle sera renvoyée dans votre instruction de lignes numériques et non dans l'instruction non numérique.
JStephen le
@JStephen Vous avez raison! Parce que la SELECT * FROM myTable WHERE col1 = 123;requête retournera des lignes, même la valeur de col est123abc
Bora
9

Cette réponse est similaire à Dmitry, mais elle autorisera les décimales ainsi que les nombres positifs et négatifs.

select * from table where col1 REGEXP '^[[:digit:]]+$'
Devpaq
la source
8

utiliser une UDF (fonction définie par l'utilisateur).

CREATE FUNCTION isnumber(inputValue VARCHAR(50))
  RETURNS INT
  BEGIN
    IF (inputValue REGEXP ('^[0-9]+$'))
    THEN
      RETURN 1;
    ELSE
      RETURN 0;
    END IF;
  END;

Puis quand vous interrogez

select isnumber('383XXXX') 

--retourne 0

select isnumber('38333434') 

- retourne 1

sélectionnez isnumber (mycol) mycol1, col2, colx dans tablex; - renverra 1 et 0 pour la colonne mycol1

- vous pouvez améliorer la fonction pour prendre des décimales, la notation scientifique, etc.

L'avantage d'utiliser un UDF est que vous pouvez l'utiliser sur le côté gauche ou droit de votre comparaison "clause where". cela simplifie grandement votre SQL avant d'être envoyé à la base de données:

 SELECT * from tablex where isnumber(columnX) = isnumber('UnkownUserInput');

J'espère que cela t'aides.

Hugo R
la source
5

Une autre alternative qui semble plus rapide que REGEXP sur mon ordinateur est

SELECT * FROM myTable WHERE col1*0 != col1;

Cela sélectionnera toutes les lignes où col1 commence par une valeur numérique.

Stian Hvatum
la source
2
Et si la valeur est zéro?
Urbycoz
1
Je suppose que vous pourriez simplement ajouter AND col1<>0pour gérer cette exception.
Urbycoz
Il est vrai que cela ne fonctionne pas pour les valeurs nulles mais cela fonctionne parfaitement pour les nombres remplis, par exemple 004. La réponse acceptée ne fonctionne pas pour les nombres remplis
Abbas
Je pense que c'est la meilleure façon de vérifier les chiffres. C'est juste que nous devons ajouter une instruction OR pour vérifier zéro, comme SELECT * FROM maTable WHERE col1 * 0! = Col1 OR col1 = '0';
Binu Raman
J'obtiens un faux positif pour '1a'. BTW: c'est équivalent à WHERE col1 <> 0- rextester.com/DJIS1493
Paul Spiegel
4

Il manque toujours cette version simple:

SELECT * FROM myTable WHERE `col1` + 0 = `col1`

(l'addition devrait être plus rapide que la multiplication)

Ou la version la plus lente pour continuer à jouer:

SELECT *, 
CASE WHEN `col1` + 0 = `col1` THEN 1 ELSE 0 END AS `IS_NUMERIC` 
FROM `myTable`
HAVING `IS_NUMERIC` = 1
Jirka Kopřiva
la source
3
Sauf erreur de compréhension, MySQL convertit n'importe quelle chaîne en 0 afin que cela ne fasse pas la distinction entre les chaînes et les nombres, les deux renverront la même chose.
Ivan McA
3
'a' + 0 = 'a'is TRUE
Paul Spiegel
3

Je recommande: si votre recherche est simple, vous pouvez utiliser `

column*1 = column

`opérateur intéressant :) est un travail et plus rapide que sur les champs varchar / char

SELECT * FROM maTable WHERE colonne * 1 = colonne;

ABC*1 => 0 (NOT EQU **ABC**)
AB15*A => 15 (NOT EQU **AB15**)
15AB => 15 (NOT EQU **15AB**)
15 => 15 (EQUALS TRUE **15**)
Ferhat KOÇER
la source
1
Êtes-vous conscient que dans MySQL, les select 'aaa123' >= 0et select '123aaa' >= 0retournent tous les deux true?
Grzegorz Smulko
1
SELECT * FROM myTable WHERE sign (col1)!=0

bien sûr, le signe (0) est zéro, mais vous pouvez alors limiter votre requête à ...

SELECT * FROM myTable WHERE sign (col1)!=0 or col1=0

MISE À JOUR: Ce n'est pas fiable à 100%, car "1abc" renverrait le signe de 1, mais "ab1c" renverrait zéro ... donc cela ne pourrait fonctionner que pour le texte qui ne commence pas par des nombres.

Miguel
la source
0

vous pouvez faire en utilisant CAST

  SELECT * from tbl where col1 = concat(cast(col1 as decimal), "")
sumit
la source
0

J'ai trouvé que cela fonctionne assez bien

if(col1/col1= 1,'number',col1) AS myInfo
Mike l'elfe
la source
C'est la même chose que pour vérifier col1 <> 0et donne un faux positif pour 1a- rextester.com/HLORBZ1242
Paul Spiegel
-1

Essayez de diviser / 1

select if(value/1>0 or value=0,'its a number', 'its not a number') from table
Diego Guidobono
la source