Cinque classi di archiviazione, non tanti tipi
SQLite salva ogni valore come una di cinque classi di archiviazione (storage class):
NULL: l'assenza di un valore.INTEGER: un numero intero con segno, da 1 a 8 byte a seconda della grandezza.REAL: un numero in virgola mobile IEEE da 8 byte.TEXT: una stringa, salvata nella codifica del database (di solito UTF-8).BLOB: byte grezzi, salvati esattamente come li hai forniti.
Tutto qui. Non c'è un BOOLEAN separato, né DATETIME, né VARCHAR, né DECIMAL. Altri database hanno decine di tipi; SQLite ne ha cinque, e tutto il resto è costruito sopra di essi.
typeof() riporta la classe di archiviazione reale di ogni valore. Vedrai integer, real, text, blob. Queste quattro, più null, sono tutto ciò che SQLite conosce.
La tipizzazione è dinamica
Ecco la parte che sorprende chi arriva da Postgres o MySQL. In SQLite (senza STRICT), il tipo che dichiari su una colonna è più un suggerimento che un contratto. Il tipo reale vive con ogni valore:
Entrambe le righe sono state accettate. La colonna id contiene un intero in una riga e del testo nell'altra; body contiene testo e un intero. SQLite salva tranquillamente valori di qualsiasi classe in qualsiasi colonna.
Questa è la tipizzazione dinamica, ed è una scelta di progetto deliberata. Rende SQLite tollerante per prototipi e script veloci. Significa anche che un errore di battitura nel codice della tua applicazione può salvare in silenzio dati della forma sbagliata per anni. Se questo compromesso ti disturba (e per la maggior parte degli schemi di produzione dovrebbe), la risposta sono le tabelle STRICT. Ci arriveremo presto.
L'affinità di tipo in un paragrafo
Il tipo dichiarato su una colonna non viene ignorato: dà alla colonna un'affinità. Quando inserisci un valore, SQLite prova a convertirlo verso l'affinità della colonna, se esiste una conversione pulita. Una colonna TEXT che riceve il numero 42 lo tiene come testo '42'; una colonna INTEGER che riceve la stringa '42' la salva come intero 42. Se la conversione perderebbe informazioni, il tipo originale viene mantenuto.
Prima riga: l'intero 42 è stato convertito nel testo '42', e la stringa '100' nell'intero 100. Seconda riga: '3.5' non poteva diventare INTEGER senza perdite, quindi è rimasta testo. L'affinità ha una pagina tutta sua in arrivo: per ora ti basta sapere che il tipo della colonna influenza comunque il salvataggio, anche se non lo impone.
Booleani
Non esiste una classe di archiviazione BOOLEAN. SQLite salva i booleani come interi: 0 per falso, 1 per vero:
Le parole chiave TRUE e FALSE vengono riconosciute (da SQLite 3.23) e tradotte in 1 e 0. La dichiarazione BOOLEAN dà alla colonna un'affinità numerica ma non la limita a 0/1: senza STRICT, potresti inserire 'maybe' e SQLite non avrebbe nulla da ridire.
Date e orari
Non esiste nemmeno DATETIME. Scegli una di tre codifiche, e le funzioni sulle date di SQLite funzionano con tutte:
TEXTin ISO-8601:'2026-04-23 14:30:00'.REALcome numeri del giorno giuliano.INTEGERcome secondi dall'epoch Unix.
Il testo ISO-8601 è la scelta più comune: si ordina correttamente come stringa, è leggibile e le funzioni integrate (date(), time(), datetime(), strftime(), julianday()) lo accettano tutte. Scegli una codifica per colonna e mantienila; mescolare formati nella stessa colonna è il genere di cosa che ti morde sei mesi dopo.
VARCHAR, CHAR e altri nomi familiari
SQLite accetta i nomi di tipo che conosci dagli altri database: VARCHAR(255), CHAR(10), NVARCHAR, DECIMAL(10,2), DOUBLE, FLOAT, INT, BIGINT, MEDIUMINT. Vengono tutti interpretati senza problemi. Semplicemente, in base alle regole di affinità, vengono ricondotti a una delle cinque classi di archiviazione.
VARCHAR(255) non impone un limite di 255 caratteri: SQLite ignora la lunghezza. DECIMAL(10, 2) non salva un decimale a precisione fissa: riceve un'affinità numerica e viene tenuto come INTEGER o REAL. Questi nomi esistono solo perché gli schemi copiati da altri database funzionino; non si portano dietro i vincoli che implicano altrove.
Se ti serve un'aritmetica decimale esatta per i soldi, salva i centesimi come INTEGER. Il REAL in virgola mobile prima o poi introdurrà errori di arrotondamento alla terza cifra decimale.
NULL è una classe di archiviazione
NULL non è solo "nessun valore": è un valore con la sua classe di archiviazione, restituita da typeof():
b risulta null. Conta perché NULL non è uguale a niente, nemmeno a un altro NULL. b = NULL non è mai vero; devi scrivere b IS NULL. L'argomento viene trattato per bene più avanti, nella pagina su operatori e NULL, ma inizia qui, con la classe di archiviazione.
Salvare byte con BLOB
BLOB salva byte grezzi così come sono: utile per piccole immagini, hash, dati codificati, qualsiasi cosa che non sia testo o un numero:
Il letterale x'...' ti permette di scrivere i blob in esadecimale in SQL; dal codice dell'applicazione, di solito passeresti un array di byte tramite un parametro. length() su un blob restituisce il numero di byte, non di caratteri.
Una nota pratica: SQLite salva senza problemi blob grandi, ma trascinare un blob da 50 MB in ogni query che tocca la riga è lento. Per i file grandi, salva il file su disco e tieni un percorso nel database.
Cosa portarti a casa
- Cinque classi di archiviazione,
NULL,INTEGER,REAL,TEXT,BLOB, coprono tutto. - I booleani sono interi; le date sono testo, real o interi (a tua scelta).
- I tipi dichiarati sulle colonne sono suggerimenti, non contratti (a meno che tu non usi
STRICT). VARCHAR(255)e simili vengono accettati ma non impongono la lunghezza o la precisione che implicano altrove.typeof(value)è tuo amico ogni volta che hai dei dubbi su cosa sia davvero salvato.
Prossimo passo: l'affinità di tipo
Il comportamento da "suggerimento" su cui siamo passati veloci ha dietro un insieme preciso di regole: cinque classi di affinità, ricavate dal nome del tipo dichiarato e applicate a ogni inserimento. È l'argomento della prossima pagina, ed è la chiave per prevedere cosa farà davvero SQLite con i valori che gli passi.
Domande frequenti
Quali tipi di dati supporta SQLite?
SQLite ha cinque classi di archiviazione: NULL, INTEGER, REAL, TEXT e BLOB. Ogni valore nel database viene salvato come una di queste. I nomi familiari come VARCHAR(255), DATETIME o BOOLEAN sono accettati in CREATE TABLE per compatibilità, ma al momento del salvataggio vengono ricondotti a una delle cinque.
SQLite ha un tipo booleano o datetime?
Non come classi di archiviazione separate. I booleani vengono salvati come INTEGER (0 e 1), anche se SQLite riconosce le parole chiave TRUE e FALSE. Date e orari vengono salvati come TEXT (stringhe ISO-8601), REAL (numeri del giorno giuliano) o INTEGER (secondi dall'epoch Unix): scegli tu la codifica, e le funzioni sulle date funzionano con tutte e tre.
Perché la tipizzazione di SQLite si dice dinamica?
Nella maggior parte dei database, una colonna dichiarata INTEGER rifiuta le stringhe. In SQLite (di default) il tipo dichiarato è un suggerimento: il tipo reale viaggia con ogni valore, quindi una colonna TEXT può contenere un intero se ne inserisci uno. Questa flessibilità a volte è utile, a volte è un'arma a doppio taglio. Le tabelle STRICT la disattivano.