218

Is there a way to detect if a value is a number in a MySQL query? Such as

SELECT * 
FROM myTable 
WHERE isANumber(col1) = true
Machavity
  • 30,841
  • 27
  • 92
  • 100
Urbycoz
  • 7,247
  • 20
  • 70
  • 108
  • I have tested the 1*col = col strategy, but somehow it fails when the query is called via PHP (returning true when it shouldn´t). In phpMyAdmin however, the hack works. This means my test behaves as expected, buy my application doesn´t. – Jahaziel Sep 27 '16 at 15:37

15 Answers15

406

You can use Regular Expression too... it would be like:

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

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

Zachary Weixelbaum
  • 904
  • 1
  • 11
  • 24
Thiago Canto
  • 4,161
  • 1
  • 15
  • 10
298

This should work in most cases.

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

It doesn't work for non-standard numbers like

  • 1e4
  • 1.2e5
  • 123. (trailing decimal)
RichardTheKiwi
  • 105,798
  • 26
  • 196
  • 262
  • Thank you. Unfortunately I need it to recognise that 123 is a number, but 123X is not. – Urbycoz Feb 21 '11 at 11:42
  • 1
    @Richard- I just read the exceptions you gave. Thought you meant the character "e". I see what you mean now. – Urbycoz Feb 21 '11 at 12:53
  • Leading zeros are not an issue for a deft sql developer --- trim(leading 0 from col1) – pim Oct 24 '14 at 18:45
  • I know it's an old post but I use this method in my query. But I've a problem, it detects "2-Power" as "2" causing trouble as it's not supposed to do that. Any idea ? – GRosay May 06 '15 at 07:05
  • @GaspardRosay What do you mean it detects? http://sqlfiddle.com/#!9/d8315/2 shows that "2-Power" is **not** detected as a number, as intended. – RichardTheKiwi May 11 '15 at 03:23
  • 1
    For trailing and leading zeros (ex. 023.12000) : concat('', col1 * 1) = '0' OR concat('', col1 * 1) = IF(LOCATE('.', col1), TRIM(BOTH '0' FROM col1), TRIM(LEADING '0' FROM col1)); – François Breton Jun 05 '15 at 15:51
  • CONCAT('', col1 * 1) is not necessary. CONCAT(col1 * 1) works as well. You don't have to pass 2 agruments to concat() function. – ElChupacabra Jun 15 '16 at 18:59
  • You don't need to concatenate with an empty string. `concat(col1 * 1) = col1` is the same (at least in newer versions). `concat(x)` works like casting to string. – Paul Spiegel Jun 06 '18 at 16:48
  • i know its an old post, but since it still ranks high on google i got here. the method in this answer actually fails on mariadb UPDATE queries, and i suggest using the proposed REGEXP in other answers – yoad w Mar 19 '19 at 08:35
  • @yoadw can you be more specific? What does it fail on in your UPDATE query? – RichardTheKiwi May 28 '19 at 01:02
  • @RichardTheKiwi i am getting "Error 1292: truncated incorrent DOUBLE value: '. it may be something specific with my db values. don't remember my research results from back then, but i gave up and used the regex approach. – yoad w May 28 '19 at 07:20
  • @RichardTheKiwi this will output the error Truncated incorrect DOUBLE value: 'x' for non convertable string, which can and will be ignored by almost everyone, but I explicitly googled this question to avoid getting this error. – LukasKroess Oct 13 '22 at 08:13
75

If your data is 'test', 'test0', 'test1111', '111test', '111'

To select all records where the data is a simple int:

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

Result: '111'

(In regex, ^ means begin, and $ means end)

To select all records where an integer or decimal number exists:

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

Result: '111' (same as last example)

Finally, to select all records where number exists, use this:

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

Result: 'test0' and 'test1111' and '111test' and '111'

Marcus Stemple
  • 120
  • 1
  • 14
Dmitriy Kozmenko
  • 1,027
  • 7
  • 14
  • 1
    I like this approach better because it's clearer and less "hackish" than the concatenation trick. Thanks! – brokethebuildagain Oct 22 '13 at 21:57
  • 10
    Not working for negative values. I'd amend the proposed regexp as follows : `REGEXP '^[+\-]?[0-9]+\\.?[0-9]*$'` – Nicolas Dec 15 '15 at 10:49
  • I'd say the "+" symbol is not necessary, you could use just a "-?", but if you want to use it, you should escape it (and the "-" symbol doesn't need to be escaped). – Thiago Canto Apr 03 '19 at 13:19
  • The `+` would be required if you're matching data like `+12.34`. There's an argument that the data should be validated before insert, but we're talking about a situation where a float has been stored as a string, so things aren't always ideal. – Aubrey Lavigne Mar 09 '23 at 18:33
18
SELECT * FROM myTable
WHERE col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$'

Will also match signed decimals (like -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;

Result:

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

Paul Spiegel
  • 30,925
  • 5
  • 44
  • 53
13

Returns numeric rows

I found the solution with following query and works for me:

SELECT * FROM myTable WHERE col1 > 0;

This query return rows having only greater than zero number column that col1

Returns non numeric rows

if you want to check column not numeric try this one with the trick (!col1 > 0):

SELECT * FROM myTable WHERE !col1 > 0;
Bora
  • 10,529
  • 5
  • 43
  • 73
  • 2
    This does not work, if you have a string that starts with a number "123abc" it will be returned in your numeric rows statement and not in the non-numeric statement. – JStephen Apr 13 '20 at 18:50
  • 1
    @JStephen You right! Because `SELECT * FROM myTable WHERE col1 = 123;` query will return rows even col value is `123abc` – Bora Apr 13 '20 at 22:33
9

This answer is similar to Dmitry, but it will allow for decimals as well as positive and negative numbers.

select * from table where col1 REGEXP '^[[:digit:]]+$'
Devpaq
  • 169
  • 4
  • 11
9

use a UDF (user defined function).

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

Then when you query

select isnumber('383XXXX') 

--returns 0

select isnumber('38333434') 

--returns 1

select isnumber(mycol) mycol1, col2, colx from tablex; -- will return 1s and 0s for column mycol1

--you can enhance the function to take decimals, scientific notation , etc...

The advantage of using a UDF is that you can use it on the left or right side of your "where clause" comparison. this greatly simplifies your SQL before being sent to the database:

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

hope this helps.

Hugo R
  • 2,613
  • 1
  • 14
  • 6
4

Another alternative that seems faster than REGEXP on my computer is

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

This will select all rows where col1 starts with a numeric value.

Stian Hvatum
  • 92
  • 2
  • 3
  • 2
    What about if the value is zero? – Urbycoz Nov 03 '14 at 08:30
  • 1
    I guess you could just add `AND col1<>0` to handle that exception. – Urbycoz Nov 03 '14 at 09:12
  • It is true that it doesn't work for zero values but it perfectly works for padded numbers, e.g. 004. The accepted answer does not work for padded numbers – Abbas Jan 15 '15 at 01:55
  • I think this is the best way to check for numbers. It's just that we need to add an OR statement for checking zero, as SELECT * FROM myTable WHERE col1*0 != col1 OR col1='0'; – Binu Raman Apr 20 '15 at 08:25
  • I get a false positive for `'1a'`. BTW: it's equivalent to `WHERE col1 <> 0` - http://rextester.com/DJIS1493 – Paul Spiegel Jul 05 '18 at 19:25
4

Still missing this simple version:

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

(addition should be faster as multiplication)

Or slowest version for further playing:

SELECT *, 
CASE WHEN `col1` + 0 = `col1` THEN 1 ELSE 0 END AS `IS_NUMERIC` 
FROM `myTable`
HAVING `IS_NUMERIC` = 1
Jirka Kopřiva
  • 2,939
  • 25
  • 28
3

You can use regular expression for the mor detail https://dev.mysql.com/doc/refman/8.0/en/regexp.html

I used this ^([,|.]?[0-9])+$. This is allows handle to the decimal and float number

SELECT
    *
FROM
    mytable
WHERE
    myTextField REGEXP "^([,|.]?[0-9])+$"
Ferhat KOÇER
  • 3,890
  • 1
  • 26
  • 26
1

I recommend: if your search is simple , you can use `

column*1 = column

` operator interesting :) is work and faster than on fields varchar/char

SELECT * FROM myTable WHERE column*1 = column;

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
  • 3,890
  • 1
  • 26
  • 26
  • 1
    Are you aware that in MySQL both the `select 'aaa123' >= 0` and `select '123aaa' >= 0` return true? – Grzegorz Smulko Jul 15 '16 at 11:38
  • @ Grzegorz Smulko is not right. SELECT 'aaa123'*1 returns to 0 it is not equal to self and SELECT '123aaa'*1 returns to 123 it is not equal to self – Ferhat KOÇER Jul 30 '20 at 22:20
  • this is a problem `SELECT '123abc' * 1 = '123abc'` will convert both sides to numbers and be TRUE because 123 = 123. We need to make sure the comparison is done as a STRING. – Garr Godfrey Dec 14 '22 at 05:27
1
SELECT * FROM myTable WHERE sign (col1)!=0

ofcourse sign(0) is zero, but then you could restrict you query to...

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

UPDATE: This is not 100% reliable, because "1abc" would return sign of 1, but "ab1c" would return zero... so this could only work for text that does not begins with numbers.

Miguel
  • 3,349
  • 2
  • 32
  • 28
0

you can do using CAST

  SELECT * from tbl where col1 = concat(cast(col1 as decimal), "")
sumit
  • 15,003
  • 12
  • 69
  • 110
0

I have found that this works quite well

if(col1/col1= 1,'number',col1) AS myInfo
Chris
  • 4,672
  • 13
  • 52
  • 93
Mike The Elf
  • 13
  • 1
  • 8
-1

Try Dividing /1

select if(value/1>0 or value=0,'its a number', 'its not a number') from table
Saravanan Sachi
  • 2,572
  • 5
  • 33
  • 42