Rileva se il valore è numero in MySQL


159

C'è un modo per rilevare se un valore è un numero in una query MySQL? Ad esempio

SELECT * 
FROM myTable 
WHERE isANumber(col1) = true

Ho testato la strategia 1 * col = col, ma in qualche modo fallisce quando la query viene chiamata tramite PHP (restituendo true quando non dovrebbe). In phpMyAdmin, tuttavia, l'hack funziona. Questo significa che il mio test si comporta come previsto, ma non comprare la mia applicazione.
Jahaziel,

Risposte:


251

Questo dovrebbe funzionare nella maggior parte dei casi.

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

Non funziona per numeri non standard come

  • 1e4
  • 1.2e5
  • 123. (decimale finale)

Grazie. Purtroppo ne ho bisogno per riconoscere che 123 è un numero, ma 123X non lo è.
Urbycoz,

1
@ Richard- Ho appena letto le eccezioni che hai dato. Pensavo intendessi il personaggio "e". Capisco cosa intendi adesso.
Urbycoz,

Gli zeri iniziali non sono un problema per uno sviluppatore sql abile --- trim (leader 0 da col1)
pimbrouwers

So che è un vecchio post ma utilizzo questo metodo nella mia query. Ma ho un problema, rileva "2-Power" come "2" causando problemi in quanto non dovrebbe farlo. Qualche idea ?
GRosay,

1
Per zeri finali e iniziali (es. 023.12000): concat ('', col1 * 1) = '0' OR concat ('', col1 * 1) = IF (LOCATE ('.', Col1), TRIM (ENTRAMBI ' 0 'DA col1), TRIM (LEADING' 0 'DA col1));
François Breton,

299

Puoi anche usare Regular Expression ... sarebbe come:

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

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


70
SELEZIONA * DA myTable DOVE col1 REGEXP '^ [0-9] + $';
Dmitriy Kozmenko,

7
La risposta accettata è davvero intelligente, ma questa risposta è più diretta e penso che dovrebbe essere la soluzione accettata.
pedromanoel,

21
Per il caso "non corrisponde": WHERE col1 NOT REGEXP...e per il caso in cui potresti avere un punto decimale, usa regex:^[0-9\.]+$
Robbie Averill

2
Inoltre non funzionerà per la notazione scientifica, funziona solo per gli ints
David Wilkins,

1
Regex migth può essere difficile da leggere per le persone che non l'hanno mai usato, ma puoi fare davvero grandi e brevi cose con esso
Olli

56

Se i tuoi dati sono 'test', 'test0', 'test1111', '111test', '111'

Per selezionare tutti i record in cui i dati sono un semplice int:

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

Risultato: '111'

(In regex, ^ significa inizio e $ significa fine)

Per selezionare tutti i record in cui esiste un numero intero o un numero decimale:

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

Risultato: '111' (uguale all'ultimo esempio)

Infine, per selezionare tutti i record in cui esiste un numero, utilizzare questo:

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

Risultato: 'test0' e 'test1111' e '111test' e '111'


Mi piace questo approccio meglio perché è più chiaro e meno "hacker" del trucco di concatenazione. Grazie!
brokethebuildagain,

8
Non funziona per valori negativi. Modificherei la regexp proposta come segue:REGEXP '^[+\-]?[0-9]+\\.?[0-9]*$'
Nicolas

Direi che il simbolo "+" non è necessario, potresti usare solo un "-?", Ma se vuoi usarlo, dovresti scappare (e il simbolo "-" non ha bisogno di essere sfuggito) .
T. Corner

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

Abbinerà anche i decimali firmati (come -1.2, +0.2, 6., 2e9, 1.2e-10 ).

Test:

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;

Risultato:

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

dimostrazione


3
Perfetto! Solo una risposta che copre effettivamente tutte le basi. Dovrebbe essere la risposta accettata.
Dom

10

Restituisce righe numeriche

Ho trovato la soluzione con la seguente query e funziona per me:

SELECT * FROM myTable WHERE col1 > 0;

Questa query restituisce righe con una colonna con un numero maggiore di zero col1

Restituisce righe non numeriche

se vuoi controllare la colonna non numerica prova questa con il trucco ( !col1 > 0):

SELECT * FROM myTable WHERE !col1 > 0;

Questo non funziona, se si dispone di una stringa che inizia con un numero "123abc", verrà restituita nell'istruzione delle righe numeriche e non nell'istruzione non numerica.
JStephen

@JStephen Hai ragione! Poiché la SELECT * FROM myTable WHERE col1 = 123;query restituirà righe anche il valore col è123abc
Bora

9

Questa risposta è simile a Dmitry, ma consentirà decimali e numeri positivi e negativi.

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

8

utilizzare un UDF (funzione definita dall'utente).

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

Quindi quando esegui una query

select isnumber('383XXXX') 

- restituisce 0

select isnumber('38333434') 

- resi 1

selezionare isnumber (mycol) mycol1, col2, colx da tablex; - restituirà 1s e 0s per la colonna mycol1

--puoi migliorare la funzione per prendere decimali, notazione scientifica, ecc ...

Il vantaggio di usare un UDF è che puoi usarlo sul lato sinistro o destro del confronto "clausola where". questo semplifica notevolmente il tuo SQL prima di essere inviato al database:

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

spero che questo ti aiuti.


5

Un'altra alternativa che sembra più veloce di REGEXP sul mio computer è

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

Questo selezionerà tutte le righe in cui col1 inizia con un valore numerico.


2
Che dire se il valore è zero?
Urbycoz,

1
Immagino che potresti semplicemente aggiungere AND col1<>0per gestire quell'eccezione.
Urbycoz,

È vero che non funziona per valori zero ma funziona perfettamente per i numeri imbottiti, ad esempio 004. La risposta accettata non funziona per i numeri imbottiti
Abbas

Penso che questo sia il modo migliore per verificare la presenza di numeri. È solo che dobbiamo aggiungere un'istruzione OR per il controllo di zero, come SELEZIONA * DA myTable DOVE col1 * 0! = Col1 OR col1 = '0';
Binu Raman,

Ottengo un falso positivo per '1a'. A proposito: è equivalente a WHERE col1 <> 0- rextester.com/DJIS1493
Paul Spiegel il

4

Manca ancora questa versione semplice:

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

(l'aggiunta dovrebbe essere più veloce come moltiplicazione)

O versione più lenta per ulteriori riproduzioni:

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

3
A meno che non abbia frainteso, MySQL converte qualsiasi stringa in uno 0 in modo che questo non distingua tra stringhe e numeri, entrambi restituiranno lo stesso.
Ivan McA,

3
'a' + 0 = 'a'è VERO
Paul Spiegel,

3

Consiglio: se la tua ricerca è semplice, puoi usare `

column*1 = column

`operatore interessante :) è lavoro e più veloce rispetto ai campi varchar / char

SELEZIONA * DA myTable DOVE colonna * 1 = colonna;

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

1
Sei consapevole del fatto che in MySQL sia il select 'aaa123' >= 0che il select '123aaa' >= 0vero ritorno?
Grzegorz Smulko,

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

ofcourse sign (0) è zero, ma puoi limitare la query a ...

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

AGGIORNAMENTO: Questo non è affidabile al 100%, perché "1abc" restituirà il segno 1, ma "ab1c" restituirà zero ... quindi potrebbe funzionare solo per il testo che non inizia con i numeri.


0

puoi fare usando CAST

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


-1

Prova a dividere / 1

select if(value/1>0 or value=0,'its a number', 'its not a number') from table
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.