Jak sprawdzić, czy wartość jest liczbą całkowitą w MySQL?

123

Widzę, że w MySQL są Cast()i Convert()funkcje do tworzenia liczb całkowitych z wartości, ale czy istnieje sposób, aby sprawdzić, czy wartość jest liczbą całkowitą? Coś jakis_int() w PHP jest tym, czego szukam.

Craig Nakamoto
źródło
2
więc niestety musimy utworzyć funkcję is_int () w MySQL
Yuda Prawira

Odpowiedzi:

215

Zakładam, że chcesz sprawdzić wartość ciągu. Jednym fajnym sposobem jest operator REGEXP, dopasowujący ciąg do wyrażenia regularnego. Po prostu zrób

select field from table where field REGEXP '^-?[0-9]+$';

to jest dość szybkie. Jeśli twoje pole jest liczbowe, po prostu przetestuj

ceil(field) = field

zamiast.

Nerwowy
źródło
4
Test „ceil (field) = field” to fajny pomysł, ale jak zauważył @Jumpy, nie powiedzie się w przypadku danych nienumerycznych: SELECT ceil („cztery”) = „cztery”; -> 1
Matthew Cornell,
3
@MatthewCornell, Powiedział, że twoje pole jest numeryczne. Dzięki temu możesz sprawdzić, czy liczba jest liczbą całkowitą. Nie będzie działać na łańcuchach, dlatego jest tam pierwsza opcja.
Malfist,
Jeśli dane mogą zawierać spacje, to się nie powiedzie. Rozważ przetestowanie trim (pole), być może z dodatkowym argumentem, aby usunąć nowe linie.
Michael Grazebrook
dane są numeryczne, może to też zrobić: select ((pole% 1) = 0);
ThiamTeck
Dzięki, ale dla porównania liczbowego myślę, że nie potrzebujesz (strcmp (ceil (pole), pole))
Alan Dixon
14

Dopasuj go do wyrażenia regularnego.

cf http://forums.mysql.com/read.php?60,1907,38488#msg-38488, jak podano poniżej:

Re: Klauzula IsNumeric () w MySQL ??
Wysłane przez: kevinclark ()
Data: 08 sierpnia 2005 13:01


Zgadzam się. Oto funkcja, którą stworzyłem dla MySQL 5:

CREATE FUNCTION IsNumeric (sIn varchar(1024)) RETURNS tinyint
RETURN sIn REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';


Pozwala to na opcjonalny znak plus / minus na początku, jeden opcjonalny separator dziesiętny i pozostałe cyfry.

JBB
źródło
Dzięki, Twoje rozwiązanie dba również o ułamki dziesiętne
Ananda
12

Załóżmy, że mamy kolumnę z polem alfanumerycznym zawierającą wpisy takie jak

a41q
1458
xwe8
1475
asde
9582
.
.
.
.
.
qe84

i chcesz mieć najwyższą wartość liczbową z tej kolumny db (w tym przypadku jest to 9582), to ta kwerenda Ci pomoże

SELECT Max(column_name) from table_name where column_name REGEXP '^[0-9]+$'
Tarun Sood
źródło
1
Wartość „10000” jest wyższa, ale zapytanie nadal zwróci wartość „9582” .
Paul Spiegel,
8

Oto proste rozwiązanie przy założeniu, że typ danych to varchar

select * from calender where year > 0

Zwróci wartość true, jeśli rok ma wartość liczbową, w przeciwnym razie fałsz

Jayjitraj
źródło
29
W varchar zwróci to również wartość true, jeśli pierwszy znak jest liczbą.
TuK,
Nie zauważyłem tego. głosowanie za komentarzem :)
Jayjitraj
8

Działa to również:

CAST( coulmn_value AS UNSIGNED ) // will return 0 if not numeric string.

na przykład

SELECT CAST('a123' AS UNSIGNED) // returns 0
SELECT CAST('123' AS UNSIGNED) // returns 123 i.e. > 0
Riad
źródło
11
co z tym SELECT CAST('12a34' AS UNSIGNED), co wraca 12?
Mike C
1
Działa to idealnie, jeśli chcesz przetestować elementy nienumeryczne, zasługuje na więcej + 1-ek. W przypadku innych odpowiedzi trudniej jest odwrócić test, aby znaleźć pozycje nienumeryczne.
DrCord,
1
@DrCord to nie działa w przypadku opisanym przez Mike'a C, stąd jest bardzo niewiarygodne
jontro
4

Aby sprawdzić, czy wartość jest Int w MySQL, możemy użyć następującego zapytania. To zapytanie da wiersze z wartościami Int

SELECT col1 FROM table WHERE concat('',col * 1) = col;
minhas23
źródło
Spowoduje to również wybranie liczb innych niż całkowite (np. „3,5” ).
Paul Spiegel,
4

Najlepsze, co mogłem wymyślić o zmiennej, to int to połączenie z funkcjami MySQL CAST()i LENGTH().
Ta metoda będzie działać na typach danych typu string, integer, double / floats.

SELECT (LENGTH(CAST(<data> AS UNSIGNED))) = (LENGTH(<data>)) AS is_int

zobacz demo http://sqlfiddle.com/#!9/ff40cd/44

nie powiedzie się, jeśli kolumna ma wartość jednego znaku. jeśli kolumna ma wartość „A”, to Cast („A” jako UNSIGNED) przyjmie wartość 0, a LENGTH (0) będzie równe 1., więc LENGTH (Cast („A” as UNSIGNED)) = LENGTH (0) będzie obliczane na 1 = 1 => 1

Prawdziwy Waqas Malik kompletnie nie mógł przetestować tej sprawy. poprawka jest.

SELECT <data>, (LENGTH(CAST(<data> AS UNSIGNED))) = CASE WHEN CAST(<data> AS UNSIGNED) = 0 THEN CAST(<data> AS UNSIGNED) ELSE (LENGTH(<data>)) END AS is_int;

Wyniki

**Query #1**

    SELECT 1, (LENGTH(CAST(1 AS UNSIGNED))) = CASE WHEN CAST(1 AS UNSIGNED) = 0 THEN CAST(1 AS UNSIGNED) ELSE (LENGTH(1)) END AS is_int;

| 1   | is_int |
| --- | ------ |
| 1   | 1      |

---
**Query #2**

    SELECT 1.1, (LENGTH(CAST(1 AS UNSIGNED))) = CASE WHEN CAST(1.1 AS UNSIGNED) = 0 THEN CAST(1.1 AS UNSIGNED) ELSE (LENGTH(1.1)) END AS is_int;

| 1.1 | is_int |
| --- | ------ |
| 1.1 | 0      |

---
**Query #3**

    SELECT "1", (LENGTH(CAST("1" AS UNSIGNED))) = CASE WHEN CAST("1" AS UNSIGNED) = 0 THEN CAST("1" AS UNSIGNED) ELSE (LENGTH("1")) END AS is_int;

| 1   | is_int |
| --- | ------ |
| 1   | 1      |

---
**Query #4**

    SELECT "1.1", (LENGTH(CAST("1.1" AS UNSIGNED))) = CASE WHEN CAST("1.1" AS UNSIGNED) = 0 THEN CAST("1.1" AS UNSIGNED) ELSE (LENGTH("1.1")) END AS is_int;

| 1.1 | is_int |
| --- | ------ |
| 1.1 | 0      |

---
**Query #5**

    SELECT "1a", (LENGTH(CAST("1.1" AS UNSIGNED))) = CASE WHEN CAST("1a" AS UNSIGNED) = 0 THEN CAST("1a" AS UNSIGNED) ELSE (LENGTH("1a")) END AS is_int;

| 1a  | is_int |
| --- | ------ |
| 1a  | 0      |

---
**Query #6**

    SELECT "1.1a", (LENGTH(CAST("1.1a" AS UNSIGNED))) = CASE WHEN CAST("1.1a" AS UNSIGNED) = 0 THEN CAST("1.1a" AS UNSIGNED) ELSE (LENGTH("1.1a")) END AS is_int;

| 1.1a | is_int |
| ---- | ------ |
| 1.1a | 0      |

---
**Query #7**

    SELECT "a1", (LENGTH(CAST("1.1a" AS UNSIGNED))) = CASE WHEN CAST("a1" AS UNSIGNED) = 0 THEN CAST("a1" AS UNSIGNED) ELSE (LENGTH("a1")) END AS is_int;

| a1  | is_int |
| --- | ------ |
| a1  | 0      |

---
**Query #8**

    SELECT "a1.1", (LENGTH(CAST("a1.1" AS UNSIGNED))) = CASE WHEN CAST("a1.1" AS UNSIGNED) = 0 THEN CAST("a1.1" AS UNSIGNED) ELSE (LENGTH("a1.1")) END AS is_int;

| a1.1 | is_int |
| ---- | ------ |
| a1.1 | 0      |

---
**Query #9**

    SELECT "a", (LENGTH(CAST("a" AS UNSIGNED))) = CASE WHEN CAST("a" AS UNSIGNED) = 0 THEN CAST("a" AS UNSIGNED) ELSE (LENGTH("a")) END AS is_int;

| a   | is_int |
| --- | ------ |
| a   | 0      |

zobacz demo

Raymond Nijland
źródło
nie powiedzie się, jeśli kolumna ma wartość jednego znaku. jeśli kolumna ma wartość „A”, to Cast („A” jako UNSIGNED) przyjmie wartość 0, a LENGTH (0) będzie równe 1., więc LENGTH (Cast („A” as UNSIGNED)) = LENGTH (0) będzie obliczane na 1 = 1 => 1
Waqas Malik
Dzięki za komentarz, że sprawa była rzeczywiście niesprawdzone @WaqasMalik pracę i testuje poprawkę teraz .. coś takiegoSELECT "a", (LENGTH(CAST("a" AS UNSIGNED))) = CASE WHEN CAST("a" AS UNSIGNED) = 0 THEN CAST("a" AS UNSIGNED) ELSE (LENGTH("a")) END AS is_int;
Raymond Nijland
To takie fajne rozwiązanie. Myślę, że to nie działa dla ujemnych liczb całkowitych, czy zmienia coś istotnego (w przypadkach skrajnych), aby przełączyć rozwiązanie na liczby całkowite ze znakiem? Testowałem, używając twoich skrzypiec jako podstawy. set @val = '1.'; SELECT @val, LENGTH(CAST(@val AS SIGNED)) = IF(CAST(@val AS SIGNED) = 0, CAST(@val AS SIGNED), LENGTH(@val)) AS is_int;Ta refaktoryzacja obsługuje wszystkie powyższe przypadki, ale nawet moja korekta nie obsługuje -1.0 lub -1. Znowu super fajne rozwiązanie.
spen.smith
3

Co powiesz na:

WHERE table.field = "0" or CAST(table.field as SIGNED) != 0

aby przetestować liczbowe i korelacyjne:

WHERE table.field != "0" and CAST(table.field as SIGNED) = 0
Tom Auger
źródło
1
CAST (table.field)! = 0 nie będzie działać, ponieważ wymaga typu do rzutowania.
Riad
Działa to idealnie, jeśli chcesz przetestować elementy nienumeryczne, zasługuje na więcej + 1-ek. W przypadku innych odpowiedzi trudniej jest odwrócić test, aby znaleźć pozycje nienumeryczne.
DrCord,
Nie działa to w przypadku liczb takich jak „0000”, „0” (spacja) i „7x” (uważane za liczbę).
Michael Grazebrook
@MichaelGrazebrook Przypuszczam, że możesz zrobić wyrażenie regularne dla dwóch pierwszych przypadków. „7x” jest uważane za liczbę? „0x7” to liczba, ale 7x?
Tom Auger,
1
@Tom Auger: Inna odpowiedź dotyczyła rozwiązań typu regex. Przez „7x jest uważane za liczbę” miałem na myśli to, że to stwierdzenie jest prawdziwe: wybierz 7 = '7q'
Michael Grazebrook
1

Próbowałem użyć wyrażeń regularnych wymienionych powyżej, ale nie działają one w następujących przypadkach:

SELECT '12 INCHES' REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$' FROM ...

Powyższe zwróci 1( TRUE), co oznacza, że ​​test łańcucha „12 cali” w porównaniu z powyższym wyrażeniem regularnym, zwraca TRUE. Wygląda jak liczba na podstawie powyższego wyrażenia regularnego. W tym przypadku, ponieważ 12 znajduje się na początku ciągu, wyrażenie regularne interpretuje ją jako liczbę.

Poniższy kod zwróci właściwą wartość (tj. 0), Ponieważ ciąg zaczyna się od znaków zamiast cyfr

SELECT 'TOP 10' REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$' FROM ...

Powyższe zwróci 0( FALSE), ponieważ początek ciągu to tekst, a nie liczba.

Jeśli jednak masz do czynienia z ciągami znaków, które zawierają kombinację cyfr i liter rozpoczynających się cyfrą, nie uzyskasz oczekiwanych wyników. REGEXP zinterpretuje ciąg jako prawidłową liczbę, podczas gdy w rzeczywistości tak nie jest.

Bill Kelly
źródło
2
To jest niepoprawne. Czy to przetestowałeś? Kiedy uruchamiam twój pierwszy przykład, zwraca on FALSE, zgodnie z oczekiwaniami, ponieważ wyrażenie regularne kończy się na, $co oznacza koniec ciągu, więc sprawdza tylko liczby, zgodnie z zamierzeniami autora.
spikyjt
1

Działa to dobrze w przypadku VARCHAR, w którym zaczyna się od liczby lub nie.

WHERE concat('',fieldname * 1) != fieldname 

mogą mieć ograniczenia, gdy dojdziesz do większych liczb NNNNE + -

PodTech.io
źródło
Wydaje się, że to nie działa dla ciągów pojedynczych znakówset @val = '5'; SELECT @val, concat('', @val * 1) != @val is_int;
spen.smith
0

dla mnie jedyne, co działa, to:

CREATE FUNCTION IsNumeric (SIN VARCHAR(1024)) RETURNS TINYINT
RETURN SIN REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';

od kevinclark wszystkie inne zwracają mi bezużyteczne rzeczy w przypadku 234jk456lub12 inches

Tim
źródło