Blog

Introduzione a SQLite

2026-06-09

Un' introduzione pratica al database SQLite per applicazioni locali

  • Database
  • SQLite
  • Programmazione

SQLite: il database che vive nel tuo file

Categoria: Database | Livello: Principiante–Intermedio


Cos'è SQLite e perché è diverso dagli altri DBMS

Quando si parla di database, la mente corre subito a sistemi complessi come MySQL o PostgreSQL: server da installare, utenti da configurare, porte da aprire. SQLite è una cosa completamente diversa.

SQLite è una libreria software che implementa un motore di database relazionale senza server (serverless). L'intero database — tabelle, indici, dati — è contenuto in un singolo file sul disco. Nessun processo in background, nessuna connessione di rete, nessuna configurazione: basta includere la libreria nel progetto e iniziare a lavorare.

> 💡 Curiosità: SQLite è probabilmente il database più diffuso al mondo. È integrato in Android, iOS, Firefox, Chrome, Python, e in migliaia di applicazioni desktop e mobili.


Architettura: serverless vs client-server

Per capire SQLite, è utile confrontarlo con un DBMS tradizionale.

Caratteristica MySQL / PostgreSQL SQLite
Architettura Client-server Serverless (libreria embeddable)
Installazione Server separato Solo un file .db
Connessione Rete TCP/IP Accesso diretto al file
Utenti e permessi Sì (complessi) Solo i permessi del filesystem
Adatto a uso concorrente Sì (molti utenti) Limitato (un writer alla volta)
Portabilità Dipende dal sistema Il file è portabile ovunque

In un sistema client-server, l'applicazione invia query attraverso la rete a un processo separato (il server) che gestisce il database. Con SQLite, invece, la libreria è incorporata direttamente nel programma: le query vengono eseguite in-process, senza intermediari.


Quando usare (e quando non usare) SQLite

✅ SQLite è la scelta giusta quando:

  • Stai sviluppando un'applicazione desktop o mobile con dati locali
  • Vuoi un prototipo veloce senza configurare un server
  • Il tuo progetto ha accessi concorrenti limitati (pochi utenti, un utente alla volta)
  • Hai bisogno di un formato di file strutturato invece di un CSV o JSON
  • Stai creando test automatizzati e vuoi un database in memoria (:memory:)
  • Stai imparando SQL e vuoi un ambiente leggero e portabile

❌ SQLite non è adatto quando:

  • Più utenti scrivono contemporaneamente sul database (es. web app ad alto traffico)
  • Hai bisogno di replicazione o clustering
  • Gestisci dataset di dimensioni multi-terabyte
  • Hai bisogno di controllo granulare degli accessi per utenti diversi

Installazione e primi passi

SQLite è disponibile su tutti i principali sistemi operativi.

Su Linux / Ubuntu

sudo apt update
sudo apt install sqlite3

Su Windows

Scarica il pacchetto precompilato da sqlite.org/download e aggiungi l'eseguibile al PATH.

Verifica dell'installazione

sqlite3 --version
# Output: 3.45.0 2024-01-15 ...

Creare un database e le prime tabelle

SQLite crea automaticamente il file database se non esiste.

sqlite3 scuola.db

Ora siamo nella shell interattiva di SQLite. Creiamo una tabella studenti:

CREATE TABLE studenti (
    id        INTEGER PRIMARY KEY AUTOINCREMENT,
    nome      TEXT    NOT NULL,
    cognome   TEXT    NOT NULL,
    classe    TEXT,
    voto_medio REAL
);

Inserimento di dati

INSERT INTO studenti (nome, cognome, classe, voto_medio)
VALUES ('Marco', 'Rossi', '4A', 7.5);

INSERT INTO studenti (nome, cognome, classe, voto_medio)
VALUES ('Giulia', 'Ferrari', '4A', 8.2);

INSERT INTO studenti (nome, cognome, classe, voto_medio)
VALUES ('Luca', 'Bianchi', '4B', 6.9);

Interrogazione dei dati

-- Tutti gli studenti
SELECT * FROM studenti;

-- Solo quelli della 4A con voto superiore a 7
SELECT nome, cognome, voto_medio
FROM studenti
WHERE classe = '4A' AND voto_medio > 7
ORDER BY voto_medio DESC;

Output:

Giulia|Ferrari|8.2
Marco|Rossi|7.5

Tipi di dato in SQLite

SQLite adotta un sistema di tipi flessibile chiamato type affinity (affinità di tipo). I tipi principali sono cinque:

Tipo SQLite Descrizione Esempio
INTEGER Intero con segno (1, 2, 4, 8 byte) id = 42
REAL Floating point a 64 bit (IEEE 754) voto = 7.5
TEXT Stringa di testo (UTF-8 o UTF-16) nome = 'Mario'
BLOB Dati binari grezzi Immagini, file
NULL Valore assente Campo non compilato

> ⚠️ Attenzione: SQLite è loosely typed. È possibile inserire una stringa in una colonna INTEGER senza errori (a meno che non venga usato STRICT). Questo comportamento, pur pratico, può essere fonte di bug in applicazioni grandi.


Comandi utili nella shell SQLite

I comandi che iniziano con . non sono SQL, ma meta-comandi della shell:

.tables              -- Elenca tutte le tabelle
.schema studenti     -- Mostra la struttura della tabella
.headers on          -- Mostra i nomi delle colonne nei risultati
.mode column         -- Formato colonne allineate
.output report.txt   -- Reindirizza output su file
.read script.sql     -- Esegue un file SQL esterno
.quit                -- Esce dalla shell

SQLite in Python: un esempio pratico

Python include SQLite nella libreria standard con il modulo sqlite3. Non serve installare nulla.

import sqlite3

# Connessione al database (viene creato se non esiste)
conn = sqlite3.connect("scuola.db")
cursor = conn.cursor()

# Creazione tabella
cursor.execute("""
    CREATE TABLE IF NOT EXISTS studenti (
        id        INTEGER PRIMARY KEY AUTOINCREMENT,
        nome      TEXT NOT NULL,
        cognome   TEXT NOT NULL,
        classe    TEXT,
        voto_medio REAL
    )
""")

# Inserimento con parametri (prevenzione SQL Injection!)
dati = [
    ("Marco",  "Rossi",   "4A", 7.5),
    ("Giulia", "Ferrari", "4A", 8.2),
    ("Luca",   "Bianchi", "4B", 6.9),
]
cursor.executemany(
    "INSERT INTO studenti (nome, cognome, classe, voto_medio) VALUES (?, ?, ?, ?)",
    dati
)
conn.commit()

# Lettura dei dati
cursor.execute("SELECT * FROM studenti WHERE voto_medio >= 7.5")
for riga in cursor.fetchall():
    print(f"{riga[1]} {riga[2]} - Classe {riga[3]} - Media: {riga[4]}")

conn.close()

Output:

Marco Rossi - Classe 4A - Media: 7.5
Giulia Ferrari - Classe 4A - Media: 8.2

> 💡 Best practice: Usa sempre i parametri (?) invece di concatenare stringhe nelle query. Questo previene gli attacchi SQL Injection.


SQL Injection: perché i parametri sono fondamentali

Considera questo codice pericoloso:

# ❌ MAI fare così
nome_input = "'; DROP TABLE studenti; --"
cursor.execute(f"SELECT * FROM studenti WHERE nome = '{nome_input}'")

La query risultante sarebbe:

SELECT * FROM studenti WHERE nome = ''; DROP TABLE studenti; --'

Un attaccante potrebbe cancellare l'intero database! Usando i parametri, SQLite tratta l'input come un semplice valore e non come codice SQL:

# ✅ Corretto: input trattato come dato, non come codice
cursor.execute("SELECT * FROM studenti WHERE nome = ?", (nome_input,))

Esercizi proposti

Esercizio 1 — Base Crea un database biblioteca.db con una tabella libri contenente: id, titolo, autore, anno, disponibile (0 o 1). Inserisci almeno 5 libri e scrivi una query che elenci solo quelli disponibili.

Esercizio 2 — Intermedio Aggiungi una seconda tabella prestiti con i campi: id, id_libro (chiave esterna), data_prestito, data_restituzione. Scrivi una query che mostri i libri attualmente in prestito (restituzione NULL).

Esercizio 3 — Avanzato Scrivi un programma Python che permetta, tramite menu testuale, di: aggiungere un libro, registrare un prestito, restituire un libro e visualizzare i libri disponibili. Usa sempre parametri per le query.


Riepilogo

Concetto Punti chiave
Architettura Serverless, tutto in un file .db
Tipi di dato INTEGER, REAL, TEXT, BLOB, NULL
Quando usarlo App locali, prototipi, test, dati strutturati monouser
Quando non usarlo Alta concorrenza, grandi dataset, multi-utente con ACL
Sicurezza Usa sempre i parametri ? per prevenire SQL Injection
Integrazione Python Modulo sqlite3 incluso nella libreria standard

Risorse per approfondire


Articolo pubblicato su filippobilardo.it — Tutti i diritti riservati