Wykryj, czy wartość jest liczbą w MySQL

159

Czy istnieje sposób na wykrycie, czy wartość jest liczbą w zapytaniu MySQL? Jak na przykład

SELECT * 
FROM myTable 
WHERE isANumber(col1) = true
Urbycoz
źródło
Przetestowałem strategię 1 * col = col, ale w jakiś sposób zawodzi, gdy zapytanie jest wywoływane przez PHP (zwraca wartość true, gdy nie powinno). Jednak w phpMyAdmin hack działa. Oznacza to, że mój test zachowuje się zgodnie z oczekiwaniami, kup moją aplikację nie.
Jahaziel

Odpowiedzi:

250

To powinno działać w większości przypadków.

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

Nie działa w przypadku niestandardowych liczb, takich jak

  • 1e4
  • 1.2e5
  • 123. (końcowe dziesiętne)
RichardTheKiwi
źródło
Dziękuję Ci. Niestety potrzebuję go, aby rozpoznać, że 123 to liczba, ale 123X nie.
Urbycoz,
1
@ Richard - właśnie przeczytałem podane przez Ciebie wyjątki. Myślałem, że masz na myśli znak „e”. Teraz rozumiem, co masz na myśli.
Urbycoz,
Zera wiodące nie są problemem dla zręcznego programisty sql --- przycinanie (wiodące 0 z col1)
pimbrouwers
Wiem, że to stary post, ale używam tej metody w zapytaniu. Ale mam problem, wykrywa problem „2-Power” jako „2”, ponieważ nie powinien tego robić. Dowolny pomysł ?
GRosay
1
Dla końcowych i wiodących zer (np. 023.12000): concat ('', col1 * 1) = '0' OR concat ('', col1 * 1) = IF (LOCATE ('.', Col1), TRIM (BOTH ') 0 'Z kol1), TRIM (WIODĄCE' 0 'Z kol1));
François Breton
299

Możesz też użyć wyrażenia regularnego ... wyglądałoby to tak:

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

Źródła: http://dev.mysql.com/doc/refman/5.1/en/regexp.html

T. Corner
źródło
70
SELECT * FROM myTable WHERE col1 REGEXP '^ [0-9] + $';
Dmitriy Kozmenko
7
Przyjęta odpowiedź jest naprawdę sprytna, ale ta odpowiedź jest bardziej bezpośrednia i myślę, że powinno to być przyjęte rozwiązanie.
pedromanoel
21
W przypadku „nie pasuje”: WHERE col1 NOT REGEXP...oraz w przypadku, gdy możesz mieć przecinek dziesiętny, użyj wyrażenia regularnego:^[0-9\.]+$
Robbie Averill
2
Nie będzie też działać dla notacji naukowej, działa tylko dla intów
David Wilkins
1
Regex może być trudny do odczytania dla ludzi, którzy go nigdy nie używali, ale można z nim robić naprawdę świetne i krótkie rzeczy
Olli
56

Jeśli Twoje dane to „test”, „test0”, „test1111”, „111test”, „111”

Aby wybrać wszystkie rekordy, w których dane są prostą liczbą int:

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

Wynik: `` 111 ''

(W wyrażeniu regularnym ^ oznacza początek, a $ oznacza koniec)

Aby wybrać wszystkie rekordy, w których istnieje liczba całkowita lub dziesiętna:

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

Wynik: „111” (tak samo jak w ostatnim przykładzie)

Na koniec, aby wybrać wszystkie rekordy, w których istnieje numer, użyj tego:

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

Wynik: „test0” i „test1111” oraz „111test” i „111”

Dmitriy Kozmenko
źródło
Bardziej podoba mi się to podejście, ponieważ jest jaśniejsze i mniej „hakerskie” niż sztuczka z konkatenacją. Dzięki!
brokethebuild ponownie
8
Nie działa dla wartości ujemnych. Zmienię proponowane wyrażenie regularne w następujący sposób:REGEXP '^[+\-]?[0-9]+\\.?[0-9]*$'
Nicolas
Powiedziałbym, że symbol „+” nie jest konieczny, możesz użyć po prostu znaku „-?”, Ale jeśli chcesz go użyć, powinieneś go uciec (a symbol „-” nie musi być zmieniony) .
T. Corner
13
SELECT * FROM myTable
WHERE col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$'

Dopasuje również liczby dziesiętne ze znakiem (np. -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;

Wynik:

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

Próbny

Paul Spiegel
źródło
3
Idealny! Tylko odpowiedź, która faktycznie obejmuje wszystkie podstawy. Powinna być zaakceptowana odpowiedź.
Dom
10

Zwraca wiersze liczbowe

Znalazłem rozwiązanie z następującym zapytaniem i działa dla mnie:

SELECT * FROM myTable WHERE col1 > 0;

To zapytanie zwraca wiersze mające tylko kolumnę z liczbą większą niż zero col1

Zwraca wiersze nienumeryczne

jeśli chcesz sprawdzić kolumnę, a nie numeryczną, spróbuj tego z trick ( !col1 > 0):

SELECT * FROM myTable WHERE !col1 > 0;
Bora
źródło
To nie działa, jeśli masz ciąg zaczynający się od liczby „123abc”, zostanie on zwrócony w instrukcji numerycznej, a nie w instrukcji nienumerycznej.
JStephen
@JStephen You right! Ponieważ SELECT * FROM myTable WHERE col1 = 123;zapytanie zwróci wiersze, nawet wartość col to123abc
Bora
9

Ta odpowiedź jest podobna do Dmitrija, ale pozwoli na ułamki dziesiętne oraz liczby dodatnie i ujemne.

select * from table where col1 REGEXP '^[[:digit:]]+$'
Devpaq
źródło
8

użyj UDF (funkcja zdefiniowana przez użytkownika).

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

Wtedy, gdy zapytasz

select isnumber('383XXXX') 

- zwroty 0

select isnumber('38333434') 

- zwroty 1

wybierz isnumber (mycol) mycol1, col2, colx z tabeli x; - zwróci 1 i 0 dla kolumny mycol1

- możesz rozszerzyć funkcję o ułamki dziesiętne, notację naukową itp.

Zaletą korzystania z funkcji UDF jest to, że można jej używać po lewej lub prawej stronie porównania „klauzula where”. to znacznie upraszcza SQL przed wysłaniem do bazy danych:

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

mam nadzieję że to pomoże.

Hugo R.
źródło
5

Inną alternatywą, która wydaje się szybsza niż REGEXP na moim komputerze, jest

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

Spowoduje to zaznaczenie wszystkich wierszy, w których col1 zaczyna się od wartości liczbowej.

Stian Hvatum
źródło
2
A co, jeśli wartość wynosi zero?
Urbycoz
1
Myślę, że możesz po prostu dodać, AND col1<>0aby obsłużyć ten wyjątek.
Urbycoz
Prawdą jest, że nie działa dla wartości zerowych, ale doskonale sprawdza się w przypadku liczb z dopełnieniem, np. 004. Zaakceptowana odpowiedź nie działa dla liczb z dopełnieniem
Abbas
Myślę, że to najlepszy sposób na sprawdzenie liczb. Po prostu musimy dodać instrukcję OR do sprawdzania zera, jako SELECT * FROM myTable WHERE kol1 * 0! = Kol1 LUB kol1 = '0';
Binu Raman
Otrzymuję fałszywie pozytywny wynik dla '1a'. BTW: to odpowiednik WHERE col1 <> 0- rextester.com/DJIS1493
Paul Spiegel
4

Wciąż brakuje tej prostej wersji:

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

(dodawanie powinno być szybsze jako mnożenie)

Lub najwolniejsza wersja do dalszej gry:

SELECT *, 
CASE WHEN `col1` + 0 = `col1` THEN 1 ELSE 0 END AS `IS_NUMERIC` 
FROM `myTable`
HAVING `IS_NUMERIC` = 1
Jirka Kopřiva
źródło
3
O ile się nie mylę, MySQL konwertuje dowolny ciąg na 0, więc nie rozróżni łańcuchów i liczb, oba zwrócą to samo.
Ivan McA
3
'a' + 0 = 'a'jest PRAWDA
Paul Spiegel,
3

Polecam: jeśli twoje wyszukiwanie jest proste, możesz użyć `

column*1 = column

`operator ciekawy :) działa i szybciej niż na polach varchar / char

SELECT * FROM myTable WHERE kolumna * 1 = kolumna;

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
źródło
1
Czy wiesz, że w MySQL zarówno the, jak select 'aaa123' >= 0i select '123aaa' >= 0return true?
Grzegorz Smulko
1
SELECT * FROM myTable WHERE sign (col1)!=0

oczywiście znak (0) wynosi zero, ale wtedy możesz ograniczyć zapytanie do ...

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

AKTUALIZACJA: Nie jest to w 100% wiarygodne, ponieważ „1abc” zwróciłoby znak 1, ale „ab1c” zwróciłoby zero… więc może to działać tylko w przypadku tekstu, który nie zaczyna się od cyfr.

Miguel
źródło
0

możesz to zrobić za pomocą CAST

  SELECT * from tbl where col1 = concat(cast(col1 as decimal), "")
sumit
źródło
0

Odkryłem, że działa to całkiem dobrze

if(col1/col1= 1,'number',col1) AS myInfo
Mike Elf
źródło
To to samo, co sprawdzenie col1 <> 0i daje fałszywie pozytywny wynik 1a- rextester.com/HLORBZ1242
Paul Spiegel.
-1

Spróbuj podzielić / 1

select if(value/1>0 or value=0,'its a number', 'its not a number') from table
Diego Guidobono
źródło