Detectar si el valor es número en MySQL

159

¿Hay alguna manera de detectar si un valor es un número en una consulta MySQL? Como

SELECT * 
FROM myTable 
WHERE isANumber(col1) = true
Urbycoz
fuente
He probado la estrategia 1 * col = col, pero de alguna manera falla cuando la consulta se llama a través de PHP (devuelve verdadero cuando no debería). Sin embargo, en phpMyAdmin, el hack funciona. Esto significa que mi prueba se comporta como se esperaba, comprar mi aplicación no.
Jahaziel

Respuestas:

251

Esto debería funcionar en la mayoría de los casos.

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

No funciona para números no estándar como

  • 1e4
  • 1.2e5
  • 123. (decimal final)
RichardTheKiwi
fuente
Gracias. Lamentablemente, necesito que reconozca que 123 es un número, pero 123X no lo es.
Urbycoz
1
@ Richard- Acabo de leer las excepciones que diste. Pensé que te referías al personaje "e". Ahora entiendo lo que quieres decir.
Urbycoz
Los ceros iniciales no son un problema para un desarrollador sql hábil --- trim (0
inicial
Sé que es una publicación antigua pero utilizo este método en mi consulta. Pero tengo un problema, detecta "2-Power" como "2" causando problemas, ya que no se supone que haga eso. Alguna idea ?
GRosay
1
Para ceros al principio y al final (ej. 023.12000): concat ('', col1 * 1) = '0' OR concat ('', col1 * 1) = IF (LOCATE ('.', Col1), TRIM (BOTH ' 0 'DESDE col1), TRIM (LEADING' 0 'DESDE col1));
François Breton
299

También puedes usar Expresión regular ... sería como:

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

Referencia: http://dev.mysql.com/doc/refman/5.1/en/regexp.html

T. Corner
fuente
70
SELECCIONE * DE myTable WHERE col1 REGEXP '^ [0-9] + $';
Dmitriy Kozmenko
77
La respuesta aceptada es realmente inteligente, pero esta respuesta es más directa, y creo que debería ser la solución aceptada.
pedromanoel
21
Para el caso de "no coincide":, WHERE col1 NOT REGEXP...y para el caso de que pueda tener un punto decimal, use regex:^[0-9\.]+$
Robbie Averill
2
Tampoco funcionará para notación científica, solo funciona para int.
David Wilkins
1
Regex migth será difícil de leer para las personas que nunca lo usaron, pero puedes hacer cosas realmente geniales y cortas con él
Olli
56

Si sus datos son 'test', 'test0', 'test1111', '111test', '111'

Para seleccionar todos los registros donde los datos son un int simple:

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

Resultado: '111'

(En regex, ^ significa comenzar y $ significa fin)

Para seleccionar todos los registros donde existe un número entero o decimal:

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

Resultado: '111' (igual que el último ejemplo)

Finalmente, para seleccionar todos los registros donde existe un número, use esto:

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

Resultado: 'test0' y 'test1111' y '111test' y '111'

Dmitriy Kozmenko
fuente
Me gusta más este enfoque porque es más claro y menos "hack" que el truco de concatenación. ¡Gracias!
brokethebuildagain
8
No funciona para valores negativos. Modificaría la expresión regular propuesta de la siguiente manera:REGEXP '^[+\-]?[0-9]+\\.?[0-9]*$'
Nicolas
Yo diría que el símbolo "+" no es necesario, podría usar solo un "-?", Pero si desea usarlo, debe escapar (y el símbolo "-" no necesita escapar) .
T. Corner
13
SELECT * FROM myTable
WHERE col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$'

También coincidirá con decimales firmados (como -1.2, +0.2, 6., 2e9, 1.2e-10 ).

Prueba:

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;

Resultado:

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

Manifestación

Paul Spiegel
fuente
3
¡Perfecto! La única respuesta que realmente cubre todas las bases. Debería ser la respuesta aceptada.
Dom
10

Devuelve filas numéricas

Encontré la solución con la siguiente consulta y funciona para mí:

SELECT * FROM myTable WHERE col1 > 0;

Esta consulta devuelve filas que solo tienen una columna de número mayor que cero que col1

Devuelve filas no numéricas

si quieres verificar la columna no numérica prueba esta con el truco ( !col1 > 0):

SELECT * FROM myTable WHERE !col1 > 0;
Bora
fuente
Esto no funciona, si tiene una cadena que comienza con un número "123abc", se devolverá en su declaración de filas numéricas y no en la declaración no numérica.
JStephen
@JStephen Tienes razón! Debido a que la SELECT * FROM myTable WHERE col1 = 123;consulta devolverá filas, incluso el valor de col es123abc
Bora
9

Esta respuesta es similar a Dmitry, pero permitirá decimales, así como números positivos y negativos.

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

use un UDF (función definida por el usuario).

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

Entonces cuando consultas

select isnumber('383XXXX') 

- devuelve 0

select isnumber('38333434') 

- devuelve 1

seleccione isnumber (mycol) mycol1, col2, colx de tablex; - devolverá 1s y 0s para la columna mycol1

- puede mejorar la función para tomar decimales, notación científica, etc.

La ventaja de usar un UDF es que puede usarlo en el lado izquierdo o derecho de su comparación de "cláusula where". Esto simplifica enormemente su SQL antes de ser enviado a la base de datos:

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

espero que esto ayude.

Hugo R
fuente
5

Otra alternativa que parece más rápida que REGEXP en mi computadora es

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

Esto seleccionará todas las filas donde col1 comienza con un valor numérico.

Stian Hvatum
fuente
2
¿Qué pasa si el valor es cero?
Urbycoz
1
Supongo que podría agregar AND col1<>0para manejar esa excepción.
Urbycoz
Es cierto que no funciona para valores cero, pero funciona perfectamente para números rellenados, por ejemplo, 004. La respuesta aceptada no funciona para números rellenados
Abbas
Creo que esta es la mejor manera de verificar los números. Es solo que necesitamos agregar una instrucción OR para verificar cero, como SELECT * FROM myTable WHERE col1 * 0! = Col1 OR col1 = '0';
Binu Raman
Me sale un falso positivo para '1a'. Por cierto: es equivalente a WHERE col1 <> 0- rextester.com/DJIS1493
Paul Spiegel
4

Todavía me falta esta versión simple:

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

(la suma debería ser más rápida como multiplicación)

O la versión más lenta para seguir jugando:

SELECT *, 
CASE WHEN `col1` + 0 = `col1` THEN 1 ELSE 0 END AS `IS_NUMERIC` 
FROM `myTable`
HAVING `IS_NUMERIC` = 1
Jirka Kopřiva
fuente
3
A menos que esté malinterpretando, MySQL convierte cualquier cadena a 0 para que esto no distinga entre cadenas y números, ambos devolverán lo mismo.
Ivan McA
3
'a' + 0 = 'a'es VERDADERO
Paul Spiegel
3

Recomiendo: si su búsqueda es simple, puede usar `

column*1 = column

`operator operator :) es trabajo y más rápido que en los campos varchar / char

SELECCIONAR * DESDE myTable WHERE columna * 1 = columna;

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
fuente
1
¿Eres consciente de que en MySQL tanto el select 'aaa123' >= 0y select '123aaa' >= 0return verdadero?
Grzegorz Smulko
1
SELECT * FROM myTable WHERE sign (col1)!=0

el signo de salida (0) es cero, pero luego podría restringir su consulta a ...

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

ACTUALIZACIÓN: Esto no es 100% confiable, porque "1abc" devolvería el signo de 1, pero "ab1c" devolvería cero ... por lo que esto solo podría funcionar para texto que no comienza con números.

Miguel
fuente
0

puedes hacerlo usando CAST

  SELECT * from tbl where col1 = concat(cast(col1 as decimal), "")
sumitir
fuente
0

He descubierto que esto funciona bastante bien

if(col1/col1= 1,'number',col1) AS myInfo
Mike el duende
fuente
Es lo mismo que verificar col1 <> 0y da un falso positivo para 1a- rextester.com/HLORBZ1242
Paul Spiegel
-1

Intenta dividir / 1

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