SQLite ma więcej matematyki, niż się wydaje
SQLite słynie z minimalizmu, ale ma pełny zestaw funkcji liczbowych: zaokrąglanie, wartość bezwzględną, zaokrąglanie w górę i w dół, potęgi, pierwiastki, logarytmy, trygonometrię i liczby losowe. Większość funkcji matematycznych dodano w SQLite 3.35 (2021), więc każda w miarę współczesna instalacja (dołączona do Pythona, Node, przodka WebSQL w twojej przeglądarce albo oficjalne CLI) ma je gotowe do użycia.
Krótka próbka na początek:
Sześć funkcji, jeden wiersz wyników. Reszta tej strony omawia, do czego służy każda grupa funkcji i jakie pułapki warto znać.
ROUND: funkcja, której użyjesz najczęściej
ROUND(value, digits) zaokrągla do podanej liczby miejsc po przecinku. Drugi argument jest opcjonalny: jeśli go pominiesz, dostaniesz zaokrąglenie do najbliższej liczby całkowitej (ale nadal jako wartość zmiennoprzecinkową):
Kilka rzeczy, na które warto zwrócić uwagę:
ROUND(3.14159)zwraca3.0, a nie3. Jeśli chcesz liczby całkowitej, użyjCAST(ROUND(x) AS INTEGER)albo po prostuCAST(x AS INTEGER), żeby obciąć część ułamkową.- SQLite zaokrągla połówki „od zera”:
2.5daje3, a-2.5daje-3. Niektóre bazy stosują zaokrąglanie bankowe (połówki do parzystej), SQLite tego nie robi. - Argument
digitsmoże być ujemny:ROUND(1234.5, -2)zaokrągla do najbliższej setki i daje1200.
W praktyce najczęściej napiszesz ROUND(price, 2) przy wyświetlaniu kwot.
ROUND a CAST: to nie to samo
Ludzie sięgają po CAST(x AS INTEGER), gdy chcą zaokrąglić, i się na tym przejeżdżają:
CAST obcina w stronę zera: po prostu wyrzuca część ułamkową. ROUND zaokrągla do najbliższej liczby całkowitej. Dla 2.9 różnica wynosi całą jednostkę. Wybierz tę funkcję, której zachowania naprawdę potrzebujesz.
ABS, SIGN i znak liczby
ABS(x) zwraca wartość bezwzględną. SIGN(x) zwraca -1, 0 albo 1 zależnie od znaku:
ABS to koń pociągowy, przydatny w zapytaniach typu „jak daleko od siebie są te dwie wartości”. SIGN jest rzadszy, ale przydaje się, gdy chcesz podzielić wiersze według kierunku (obciążenie a uznanie, zysk a strata) bez jawnego CASE.
CEIL, FLOOR i TRUNC
Te funkcje dają wartości całkowite bez zaokrąglania do najbliższej. CEIL zawsze idzie w górę, FLOOR zawsze w dół, a TRUNC zawsze w stronę zera:
Uważaj na liczby ujemne. FLOOR(-2.9) to -3 (dalej od zera), ale TRUNC(-2.9) to -2 (w stronę zera). Przy liczbach ujemnych FLOOR i TRUNC dają różne wyniki, a wybór złej funkcji to klasyczny błąd o jeden.
CEILING to alias CEIL. Używaj zapisu, który lepiej ci się czyta.
Dzielenie całkowite to prawdziwa pułapka
To nie funkcja, tylko operator /, ale początkujących łapie częściej niż którakolwiek z prawdziwych funkcji matematycznych:
Gdy obie strony są liczbami całkowitymi, SQLite wykonuje dzielenie całkowite i obcina wynik. Gdy tylko jedna strona jest REAL, całe wyrażenie staje się rzeczywiste. Rozwiązanie: upewnij się, że co najmniej jeden argument jest zmiennoprzecinkowy, pisząc 2.0 zamiast 2 albo stosując rzutowanie.
Najbardziej boli to przy odwołaniach do kolumn: total_cents / 100 zwraca liczbę całkowitą. total_cents / 100.0 zwraca kwotę w dolarach, o którą naprawdę chodziło.
MOD i operator %
MOD(x, y) zwraca resztę z dzielenia x / y. Operator % robi to samo:
MOD(17, 5) i 17 % 5 zwracają 2. Reszta z dzielenia przez zero zwraca w SQLite NULL, a nie błąd, co jest nietypowe w porównaniu z większością języków. Jeśli ma to dla ciebie znaczenie, najpierw sprawdź dzielnik albo opakuj wywołanie w CASE WHEN y = 0 THEN ... END.
Forma funkcji i operatora są wymienne. Większość osób wybiera %, bo jest krótszy.
POWER, SQRT, EXP, LOG
Do potęg i pierwiastków:
Kilka uwag, na które ludzie się łapią:
POWto aliasPOWER.LOG(x)w SQLite ma podstawę 10.LN(x)to logarytm naturalny.LOG(b, x)z dwoma argumentami to logarytm o podstawieb. (To różni się od wielu języków, w którychlogto logarytm naturalny: wygrała konwencja SQL.)SQRTz liczby ujemnej zwracaNULL, a nie błąd.POWER(0, 0)zwraca umownie1.
Przydają się przy procencie składanym, przeliczaniu na decybele, liczeniu odległości, wszędzie tam, gdzie pojawia się matematyka geometryczna lub wykładnicza.
RANDOM i RANDOMBLOB
RANDOM() zwraca 64-bitową liczbę całkowitą ze znakiem, z całego jej zakresu:
Żeby dostać liczbę z przedziału, opakuj wynik w ABS (bo RANDOM() ma znak) i użyj %. Żeby dostać liczbę rzeczywistą między 0 a 1, podziel przez największą 64-bitową liczbę całkowitą. SQLite nie ma wbudowanego RAND() zwracającego wartość od 0 do 1: budujesz ją sam.
RANDOMBLOB(n) zwraca n bajtów losowych danych, przydatnych do generowania tokenów sesji albo danych testowych. Połącz z HEX(), żeby dostać napis nadający się do wyświetlenia:
Każde wywołanie daje nową wartość. Nie oczekuj, że RANDOM() zwróci dwa razy tę samą liczbę w tym samym wierszu: nawet w obrębie jednego wyrażenia każde wywołanie jest niezależne.
Wszystko razem
Mały przykład: obliczanie wartości i zaokrąglanie cen w tabeli produktów.
Kluczowy fragment to price_cents / 100.0: to .0 sprawia, że dzielenie jest rzeczywiste, a potem ROUND formatuje wynik do dwóch miejsc po przecinku. Bez tego 1299 / 100 dałoby 12, a nie 12.99.
Dalej: data i czas
Funkcje liczbowe zajmują się matematyką. Daty i godziny potrzebują własnego zestawu narzędzi: SQLite przechowuje je jako tekst, liczbę rzeczywistą albo całkowitą i daje niewielki, ale sprawny zestaw funkcji do ich parsowania, formatowania i obliczeń. O tym w następnej części.
Najczęściej zadawane pytania
Jak zaokrąglić do 2 miejsc po przecinku w SQLite?
Użyj ROUND(value, 2). Drugi argument to liczba zachowywanych miejsc po przecinku: ROUND(3.14159, 2) zwraca 3.14. Z jednym argumentem ROUND(x) zaokrągla do najbliższej liczby całkowitej, ale nadal zwraca wartość zmiennoprzecinkową, co bywa zaskoczeniem.
Czy SQLite ma CEIL i FLOOR?
Tak, od SQLite 3.35 (2021) funkcje matematyczne są wbudowane: CEIL(x), FLOOR(x), SQRT(x), POWER(x, y), LOG(x), EXP(x) i inne. W starszych wersjach nie są dostępne bez wczytania rozszerzenia matematycznego, ale większość współczesnych instalacji (Python, Node, przeglądarki) ma je włączone.
Dlaczego 5 / 2 zwraca 2 w SQLite?
Ponieważ oba argumenty są liczbami całkowitymi, SQLite wykonuje dzielenie całkowite i obcina wynik. Zamień jedną stronę na REAL (5 / 2.0 albo CAST(5 AS REAL) / 2), żeby dostać 2.5. To nie dziwactwo funkcji liczbowych, tylko zachowanie operatora / przy argumentach całkowitych.