SQLite ha più matematica di quanto pensi
SQLite è noto per essere minimale, ma include un set completo di funzioni numeriche: arrotondamento, valore assoluto, arrotondamento per eccesso e per difetto, potenze, radici, logaritmi, trigonometria, numeri casuali. La maggior parte delle funzioni matematiche è stata aggiunta in SQLite 3.35 (2021), quindi qualsiasi installazione ragionevolmente moderna (quella inclusa in Python, in Node, l'antenato WebSQL del tuo browser o la CLI ufficiale) le ha già pronte.
Ecco un assaggio prima di entrare nel dettaglio:
Sei funzioni, una riga di risultati. Il resto della pagina spiega a cosa serve ogni famiglia di funzioni e le insidie da conoscere.
ROUND: quella che userai di più
ROUND(value, digits) arrotonda a un certo numero di cifre decimali. Il secondo argomento è facoltativo: se lo ometti, arrotondi all'intero più vicino (ma sempre come valore in virgola mobile):
Alcune cose da notare:
ROUND(3.14159)restituisce3.0, non3. Se vuoi un intero, usaCAST(ROUND(x) AS INTEGER), oppure semplicementeCAST(x AS INTEGER)per troncare.- SQLite arrotonda la metà allontanandosi dallo zero:
2.5diventa3,-2.5diventa-3. Alcuni database usano l'arrotondamento bancario (la metà va al pari più vicino); SQLite no. - L'argomento
digitspuò essere negativo:ROUND(1234.5, -2)arrotonda al centinaio più vicino e dà1200.
In pratica scriverai ROUND(price, 2) per mostrare importi di denaro più di qualsiasi altra cosa.
ROUND e CAST: non sono la stessa cosa
Molti usano CAST(x AS INTEGER) quando in realtà vogliono arrotondare, e ci cascano:
CAST tronca verso lo zero: butta semplicemente via la parte frazionaria. ROUND arrotonda all'intero più vicino. Per 2.9 la differenza è di un'unità intera. Scegli quella che fa davvero ciò che ti serve.
ABS, SIGN e il segno di un numero
ABS(x) restituisce il valore assoluto. SIGN(x) restituisce -1, 0 o 1 a seconda del segno:
ABS è il cavallo da tiro, comodo per le query del tipo "quanto distano questi due valori". SIGN è meno comune, ma utile quando vuoi raggruppare le righe per direzione (addebito o accredito, guadagno o perdita) senza un CASE esplicito.
CEIL, FLOOR e TRUNC
Queste ti danno valori interi senza arrotondare al più vicino. CEIL va sempre verso l'alto, FLOOR sempre verso il basso, TRUNC sempre verso lo zero:
Attenzione ai casi negativi. FLOOR(-2.9) è -3 (più lontano dallo zero), ma TRUNC(-2.9) è -2 (verso lo zero). Con i numeri negativi FLOOR e TRUNC non concordano, e scegliere quella sbagliata è un classico errore di uno.
CEILING è un alias di CEIL. Usa la grafia che ti sembra più leggibile.
La divisione intera è la vera trappola
Non è una funzione, è l'operatore /, ma mette in difficoltà i principianti più di qualsiasi funzione matematica vera e propria:
Quando entrambi i lati sono interi, SQLite esegue una divisione intera e tronca. Appena uno dei due lati è un REAL, l'intera espressione diventa reale. La soluzione è assicurarsi che almeno un operando sia in virgola mobile, scrivendo 2.0 invece di 2 oppure con un cast.
Il problema morde di più con i riferimenti alle colonne: total_cents / 100 restituisce un intero. total_cents / 100.0 restituisce l'importo in dollari che volevi davvero.
MOD e l'operatore %
MOD(x, y) restituisce il resto di x / y. L'operatore % fa la stessa cosa:
MOD(17, 5) e 17 % 5 restituiscono entrambi 2. Il modulo per zero in SQLite restituisce NULL: non solleva un errore, il che è insolito rispetto alla maggior parte dei linguaggi. Se per te conta, controlla prima il divisore o racchiudi la chiamata in CASE WHEN y = 0 THEN ... END.
La forma funzione e la forma operatore sono intercambiabili. Quasi tutti usano % perché è più breve.
POWER, SQRT, EXP, LOG
Per esponenti e radici:
Alcune note che colgono molti di sorpresa:
POWè un alias diPOWER.- In SQLite
LOG(x)è in base 10.LN(x)è il logaritmo naturale.LOG(b, x)con due argomenti è il logaritmo in baseb. (È diverso da molti linguaggi in cuilogè il logaritmo naturale: qui ha vinto la convenzione SQL.) SQRTdi un numero negativo restituisceNULL, non un errore.POWER(0, 0)restituisce1per convenzione.
Sono utili per l'interesse composto, per normalizzare in decibel, per calcolare distanze: ovunque compaia matematica geometrica o esponenziale.
RANDOM e RANDOMBLOB
RANDOM() restituisce un intero con segno a 64 bit, in qualsiasi punto del suo intervallo completo:
Per ottenere un numero in un intervallo, avvolgi con ABS (perché RANDOM() ha il segno) e usa %. Per ottenere un numero reale tra 0 e 1, dividi per il massimo intero a 64 bit. SQLite non ha una funzione RAND() integrata che restituisca un valore tra 0 e 1: te la costruisci da solo.
RANDOMBLOB(n) restituisce n byte di dati casuali, utili per generare token di sessione o fixture di test. Combinala con HEX() per ottenere una stringa stampabile:
Ogni chiamata produce un valore nuovo. Non aspettarti che RANDOM() restituisca due volte lo stesso numero nella stessa riga: anche dentro un'unica espressione, ogni invocazione è indipendente.
Mettere tutto insieme
Un piccolo esempio completo: calcolare distanze e arrotondare i prezzi in una tabella di prodotti.
Il punto chiave è price_cents / 100.0: quel .0 rende reale la divisione, poi ROUND la formatta a due decimali. Senza, 1299 / 100 ti darebbe 12, non 12.99.
Prossimo passo: date e orari
Le funzioni numeriche si occupano della matematica. Date e orari hanno bisogno di strumenti propri: SQLite li memorizza come testo, reale o intero, e ti offre un insieme piccolo ma capace di funzioni per analizzarli, formattarli e fare calcoli su di essi. È il prossimo argomento.
Domande frequenti
Come arrotondo a 2 decimali in SQLite?
Usa ROUND(value, 2). Il secondo argomento è il numero di cifre decimali da tenere: ROUND(3.14159, 2) restituisce 3.14. Con un solo argomento, ROUND(x) arrotonda all'intero più vicino ma restituisce comunque un valore in virgola mobile, e questo sorprende molti.
SQLite ha CEIL e FLOOR?
Sì, da SQLite 3.35 (2021) le funzioni matematiche sono integrate: CEIL(x), FLOOR(x), SQRT(x), POWER(x, y), LOG(x), EXP(x) e simili. Nelle build più vecchie non sono disponibili a meno di caricare l'estensione matematica, ma la maggior parte delle installazioni moderne (Python, Node, browser) le include già attive.
Perché 5 / 2 restituisce 2 in SQLite?
Perché entrambi gli operandi sono interi, quindi SQLite esegue una divisione intera e tronca il risultato. Converti uno dei due lati in REAL, con 5 / 2.0 o CAST(5 AS REAL) / 2, per ottenere 2.5. Non è una stranezza delle funzioni numeriche: è il comportamento dell'operatore / con argomenti interi.