Detectar se o valor é o número no MySQL


159

Existe uma maneira de detectar se um valor é um número em uma consulta MySQL? Tal como

SELECT * 
FROM myTable 
WHERE isANumber(col1) = true

Eu testei a estratégia 1 * col = col, mas de alguma forma falha quando a consulta é chamada via PHP (retornando true quando não deveria). No phpMyAdmin, no entanto, o hack funciona. Isso significa que meu teste se comporta conforme o esperado, comprar meu aplicativo não.
27416

Respostas:


249

Isso deve funcionar na maioria dos casos.

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

Não funciona para números fora do padrão, como

  • 1e4
  • 1.2e5
  • 123. (decimal à direita)

Obrigado. Infelizmente, preciso reconhecer que 123 é um número, mas 123X não é.
precisa saber é o seguinte

1
@ Richard- Acabei de ler as exceções que você deu. Pensei que você quis dizer o personagem "e". Entendo o que você quer dizer agora.
precisa saber é o seguinte

Zeros à esquerda não são um problema para um desenvolvedor hábil sql --- Trim (principais 0 de col1)
pimbrouwers

Eu sei que é um post antigo, mas eu uso esse método na minha consulta. Mas eu tenho um problema, ele detecta "2-Power" como "2", causando problemas, pois não deveria fazer isso. Qualquer ideia ?
Grosay

1
Para zeros à direita e à esquerda (ex. 023.12000): concat ('', col1 * 1) = '0' OU concat ('', col1 * 1) = SE (LOCATE ('.', Col1), TRIM (AMBOS '') 0 'FROM col1), TRIM (LÍDER' 0 'FROM col1));
François Breton

299

Você também pode usar Expressão Regular ... seria como:

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

Referência: http://dev.mysql.com/doc/refman/5.1/en/regexp.html


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

7
A resposta aceita é realmente inteligente, mas é mais direta e acho que deve ser a solução aceita.
pedromanoel 30/10

21
Para o caso de "não corresponde": WHERE col1 NOT REGEXP...e para o caso em que você pode ter um ponto decimal, use regex:^[0-9\.]+$
Robbie Averill

2
Também não vai funcionar para notação científica, só funciona para ints
David Wilkins

1
Regex migth ser difícil de ler para pessoas que nunca usei, mas você pode fazer realmente grandes e curtas coisas com ele
Olli

56

Se seus dados forem 'test', 'test0', 'test1111', '111test', '111'

Para selecionar todos os registros em que os dados são simples:

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

Resultado: '111'

(No regex, ^ significa começo e $ significa fim)

Para selecionar todos os registros onde existe um número inteiro ou decimal:

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

Resultado: '111' (igual ao último exemplo)

Por fim, para selecionar todos os registros onde o número existe, use o seguinte:

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

Resultado: 'test0' e 'test1111' e '111test' e '111'


Eu gosto mais dessa abordagem porque é mais clara e menos "hackiana" do que o truque de concatenação. Obrigado!
brokethebuildagain

8
Não está funcionando para valores negativos. Eu alteraria o regexp proposto da seguinte maneira:REGEXP '^[+\-]?[0-9]+\\.?[0-9]*$'
Nicolas

Eu diria que o símbolo "+" não é necessário, você pode usar apenas um "-?", Mas se quiser usá-lo, deve escapar dele (e o símbolo "-" não precisa ser escapado) .
T. canto

13
SELECT * FROM myTable
WHERE col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$'

Também corresponderá às casas decimais assinadas (como -1,2, +0,2, 6., 2e9, 1,2e-10 ).

Teste:

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

Demo


3
Perfeito! Apenas responda que realmente cobre todas as bases. Deve ser a resposta aceita.
Dom

10

Retorna linhas numéricas

Encontrei a solução com a seguinte consulta e funciona para mim:

SELECT * FROM myTable WHERE col1 > 0;

Esta consulta retorna linhas com apenas uma coluna numérica maior que zero col1

Retorna linhas não numéricas

se você quiser verificar a coluna não numérica, tente esta com o truque ( !col1 > 0):

SELECT * FROM myTable WHERE !col1 > 0;

Isso não funciona, se você tiver uma sequência que começa com o número "123abc", ela será retornada na instrução de linhas numéricas e não na instrução não numérica.
JStephen 13/04

@JStephen Você está certo! Como a SELECT * FROM myTable WHERE col1 = 123;consulta retornará linhas, o valor da coluna é123abc
Bora

9

Essa resposta é semelhante a Dmitry, mas permitirá números decimais, além de números positivos e negativos.

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

8

use um UDF (função definida pelo usuário).

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

Então, quando você consulta

select isnumber('383XXXX') 

- retornos 0

select isnumber('38333434') 

--returns 1

selecione isnumber (mycol) mycol1, col2, colx de tablex; - retornará 1s e 0s para a coluna mycol1

- você pode aprimorar a função para obter decimais, notação científica, etc ...

A vantagem de usar um UDF é que você pode usá-lo no lado esquerdo ou direito da sua comparação "cláusula where". isso simplifica bastante o seu SQL antes de ser enviado ao banco de dados:

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

espero que isto ajude.


5

Outra alternativa que parece mais rápida que o REGEXP no meu computador é

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

Isso selecionará todas as linhas em que col1 começa com um valor numérico.


2
E se o valor for zero?
Urbycoz

1
Eu acho que você poderia adicionar AND col1<>0para lidar com essa exceção.
precisa saber é o seguinte

É verdade que ele não funciona com valores zero, mas funciona perfeitamente para números preenchidos, por exemplo, 004. A resposta aceita não funciona para números preenchidos
Abbas

Eu acho que essa é a melhor maneira de procurar números. É só que precisamos adicionar uma instrução OR para verificar zero, como SELECT * FROM myTable WHERE col1 * 0! = Col1 OR col1 = '0';
precisa saber é o seguinte

Eu recebo um falso positivo por '1a'. BTW: é equivalente a WHERE col1 <> 0- rextester.com/DJIS1493
Paul Spiegel

4

Ainda falta esta versão simples:

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

(a adição deve ser mais rápida como multiplicação)

Ou versão mais lenta para continuar jogando:

SELECT *, 
CASE WHEN `col1` + 0 = `col1` THEN 1 ELSE 0 END AS `IS_NUMERIC` 
FROM `myTable`
HAVING `IS_NUMERIC` = 1

3
A menos que eu esteja entendendo errado, o MySQL converte qualquer string em 0, para que isso não faça distinção entre strings e números, ambos retornarão o mesmo.
Ivan McA

3
'a' + 0 = 'a'é VERDADEIRO
Paul Spiegel

3

Eu recomendo: se sua pesquisa for simples, você pode usar o `

column*1 = column

`operador interessante :) é trabalho e mais rápido do que nos campos varchar / char

SELECT * FROM myTable WHERE coluna * 1 = coluna;

ABC*1 => 0 (NOT EQU **ABC**)
AB15*A => 15 (NOT EQU **AB15**)
15AB => 15 (NOT EQU **15AB**)
15 => 15 (EQUALS TRUE **15**)

1
Você está ciente de que, no MySQL, the select 'aaa123' >= 0e select '123aaa' >= 0return true?
Grzegorz Smulko

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

O sinal de curso (0) é zero, mas você pode restringir sua consulta a ...

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

UPDATE: Isso não é 100% confiável, porque "1abc" retornaria o sinal 1, mas "ab1c" retornaria zero ... portanto, isso só funcionaria para textos que não começam com números.


0

você pode fazer usando CAST

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


-1

Tente dividir / 1

select if(value/1>0 or value=0,'its a number', 'its not a number') from table
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.