← Torna alla serieSviluppo web da zero Β· 18 / 24

Query SQL di base


Le tabelle ci sono, le chiavi pure. Ora serve la lingua per parlare col database: si chiama SQL (Structured Query Language), ha cinquant'anni portati benissimo, ed Γ¨ probabilmente la competenza con il miglior rapporto sforzo/durata di tutta l'informatica: quello che impari oggi valeva nel 1980 e varrΓ  nel 2050.


E c'è una cosa che ti farà sorridere: SQL è un linguaggio dichiarativo. Dici cosa vuoi, non come ottenerlo: al piano di esecuzione pensa il database. Ti ricorda qualcosa? È la stessa filosofia dei framework frontend del capitolo 9. Te l'avevo detto che le buone idee girano.


πŸ” SELECT: leggere


Il comando che scriverai piΓΉ di tutti nella vita:

SQL
1-- tutto il registro
2SELECT * FROM guardiani;
3
4-- solo alcune colonne
5SELECT nome, ruolo FROM guardiani;

L'asterisco Γ¨ "tutte le colonne". Ma il potere vero arriva con i filtri:

SQL
1-- solo le reclute
2SELECT * FROM guardiani WHERE ruolo = 'recluta';
3
4-- le reclute del castello 1, in ordine alfabetico, massimo 10
5SELECT * FROM guardiani
6WHERE ruolo = 'recluta' AND castello_id = 1
7ORDER BY nome
8LIMIT 10;

WHERE filtra le righe, ORDER BY le ordina, LIMIT ne prende un numero massimo. Si legge come una frase: "dammi i guardiani dove il ruolo Γ¨ recluta, ordinati per nome, al massimo dieci". Dichiarativo, appunto.


✍️ INSERT, UPDATE, DELETE: scrivere


Gli altri tre si presentano da soli, anche perchΓ© li conosci giΓ  sotto mentite spoglie:

SQL
1-- Create: arruolamento
2INSERT INTO guardiani (nome, ruolo, castello_id)
3VALUES ('Grenn', 'recluta', 1);
4
5-- Update: promozione
6UPDATE guardiani SET ruolo = 'ranger' WHERE id = 3;
7
8-- Delete: congedo
9DELETE FROM guardiani WHERE id = 3;

Esatto: è il CRUD del capitolo 12, nella sua lingua madre. INSERT è Create, SELECT è Read, UPDATE e DELETE si chiamano proprio così. I verbi HTTP erano la mappatura per il web; SQL è la mappatura per i dati.

Ora guarda di nuovo UPDATE e DELETE, e nota il WHERE. Adesso immaginali senza: DELETE FROM guardiani cancella tutte le righe. Nessuna conferma, nessun cestino. Ogni sviluppatore ha una storia dell'orrore che inizia con un WHERE dimenticato: scrivilo prima del resto della query, e sui database veri, prova prima con una SELECT.

🀝 JOIN: interrogare le relazioni


Le chiavi esterne del capitolo scorso servivano a questo momento. "Dammi i guardiani con il nome del loro castello" richiede dati da due tabelle, e il ponte si chiama JOIN:

SQL
SELECT guardiani.nome, guardiani.ruolo, castelli.nome AS castello
FROM guardiani
JOIN castelli ON guardiani.castello_id = castelli.id;

Leggilo con calma: prendi i guardiani, agganciali ai castelli dove la chiave esterna incontra la chiave primaria, e dammi le colonne di entrambi (AS rinomina, per non confondere i due nome). Risultato:

TEXT
1β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
2β”‚ nome           β”‚ ruolo           β”‚ castello          β”‚
3β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
4β”‚ Jon Snow       β”‚ lord comandante β”‚ Castello Nero     β”‚
5β”‚ Samwell Tarly  β”‚ attendente      β”‚ Castello Nero     β”‚
6β”‚ Eddison Tollet β”‚ recluta         β”‚ Forte Orientale   β”‚
7β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

I JOIN hanno varianti e profonditΓ  che scoprirai col tempo; per ora ti basta questo, che copre una quantitΓ  sorprendente di casi reali.


πŸ’‰ La promessa mantenuta: ecco la SQL injection


Nel capitolo sulla sicurezza ti ho promesso che avresti visto coi tuoi occhi perchΓ© "mai fidarsi del client" Γ¨ questione di vita o di morte. Il momento Γ¨ arrivato.


Immagina un login che costruisce la query incollando l'input dell'utente nella stringa:

JAVASCRIPT
// ⚠️ NON FARLO MAI: è l'esempio di come NON si fa
const query = "SELECT * FROM utenti WHERE nome = '" + input + "'";

Con un input normale (Jon), tutto bene. Ma un malintenzionato non scrive un nome. Scrive questo:

TEXT
' OR '1'='1

Incollalo mentalmente nella stringa e guarda cosa diventa la query:

SQL
SELECT * FROM utenti WHERE nome = '' OR '1'='1'

'1'='1' Γ¨ sempre vero: la query restituisce tutti gli utenti. Con varianti dello stesso trucco si scavalcano login, si leggono dati altrui, si cancellano tabelle intere. Questa Γ¨ la SQL injection: da vent'anni stabilmente sul podio delle vulnerabilitΓ  piΓΉ sfruttate al mondo. Non perchΓ© sia sofisticata, ma perchΓ© Γ¨ facile da commettere.

La difesa esiste, Γ¨ semplice e la vedrai nel prossimo capitolo: mai costruire query concatenando input dell'utente. I dati viaggiano separati dal comando, con le query parametrizzate. Tienilo a mente ancora per qualche pagina.

βœ… Conclusione


Ora parli la lingua dei dati: SELECT con filtri, ordinamenti e limiti, INSERT, UPDATE e DELETE (con rispetto per il WHERE), e il JOIN che trasforma le relazioni in risposte. E sai riconoscere l'attacco piΓΉ famoso del web, che Γ¨ giΓ  metΓ  della difesa.


Resta l'ultimo miglio: far parlare il nostro server Fastify con un database vero. Nel prossimo capitolo chiudiamo il cerchio aperto sei capitoli fa: Samwell sta per smettere di sparire.

Sviluppatore fullstack a Milano. Scrivo di Angular, ecosistema JavaScript e AI.