Impara Basi di dati e SQL da zero
1Che cos’è un database relazionale
Un database relazionale memorizza i dati in tabelle. Una tabella assomiglia a un foglio di calcolo: ogni riga è un record, ogni colonna è una proprietà.
Un negozio potrebbe avere una tabella customers con le colonne id, name e city, e una tabella orders con le colonne id, customer_id e total.
Una chiave primaria è una colonna, o un insieme di colonne, che identifica in modo univoco ogni riga. Non può mai essere ripetuta e non può mai essere vuota. Qui è l’id di ciascuna tabella.
Una chiave esterna è una colonna che fa riferimento alla chiave primaria di un’altra tabella. In orders, customer_id dice quale cliente ha effettuato l’ordine.
Così le tabelle sono collegate: un cliente può avere molti ordini, ma ogni ordine appartiene a un solo cliente. Questa è una relazione uno-a-molti.
SQL (Structured Query Language) è il linguaggio che usi per creare tabelle, modificare dati e fare domande su di essi.
Autoverifica Che cos’è una chiave primaria?
- La prima colonna di ogni tabella
- Un indice che rende più veloci le ricerche
- Una colonna che fa riferimento a una riga di un’altra tabella
- Una colonna o un insieme di colonne che identifica in modo univoco ogni riga
Risposta: Una colonna o un insieme di colonne che identifica in modo univoco ogni riga. Una chiave primaria è univoca e mai NULL, quindi individua esattamente una riga. Una colonna che fa riferimento a un’altra tabella è una chiave esterna.
2Leggere i dati con SELECT
La maggior parte delle domande riguarda l’istruzione SELECT. È costruita con clausole, sempre scritte in quest’ordine:
SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY …
- SELECT elenca le colonne che vuoi. DISTINCT elimina le righe duplicate.
- FROM indica la tabella, o le tabelle unite.
- WHERE mantiene solo le righe che soddisfano una condizione, per esempio WHERE total > 20.
- GROUP BY raggruppa le righe con lo stesso valore, così puoi contare o sommare per gruppo.
- HAVING mantiene solo i gruppi che soddisfano una condizione. Può usare le aggregazioni, cosa che WHERE non può fare.
- ORDER BY ordina il risultato, in ordine crescente per impostazione predefinita; aggiungi DESC per avere prima i più alti.
Le funzioni di aggregazione riassumono molte righe in un solo valore: COUNT, SUM, AVG, MIN e MAX.
Il database non esegue le clausole nell’ordine in cui le scrivi. Esegue prima FROM, poi WHERE, GROUP BY, HAVING, SELECT e infine ORDER BY.
Altre istruzioni modificano i dati: INSERT aggiunge righe, UPDATE modifica righe e DELETE elimina righe. CREATE, ALTER e DROP modificano le tabelle stesse.
Autoverifica Vuoi solo i clienti con più di 5 ordini. Quale clausola filtra su COUNT(*) > 5?
- DISTINCT
- HAVING
- ORDER BY
- WHERE
Risposta: HAVING. Il conteggio esiste solo dopo che le righe sono state raggruppate, e HAVING filtra i gruppi. WHERE viene eseguita prima del raggruppamento, quindi non può usare un’aggregazione come COUNT.
3Join, normalizzazione e transazioni
Un join combina le righe di due tabelle usando una condizione, di solito chiave esterna = chiave primaria:
FROM customers c JOIN orders o ON o.customer_id = c.id
- INNER JOIN (o JOIN) mantiene solo le righe che hanno una corrispondenza in entrambe le tabelle.
- LEFT JOIN mantiene ogni riga della tabella di sinistra. Dove non c’è corrispondenza, le colonne della tabella di destra sono NULL.
- NULL significa che un valore manca o è sconosciuto. Verificalo con IS NULL, mai con = NULL.
La normalizzazione divide le tabelle in modo che ogni fatto sia memorizzato una sola volta. Così si evita di aggiornare lo stesso fatto in più posti.
- 1NF: ogni cella contiene un valore atomico, senza gruppi ripetuti.
- 2NF: 1NF, e ogni colonna non chiave dipende dall’intera chiave, non da una parte di una chiave composta.
- 3NF: 2NF, e nessuna colonna non chiave dipende da un’altra colonna non chiave.
Una transazione raggruppa le istruzioni in un’unica unità. COMMIT la rende permanente e ROLLBACK la annulla. Le transazioni seguono le proprietà ACID: atomicità (tutto o niente), coerenza, isolamento e durabilità.
Autoverifica Un cliente non ha effettuato ordini. Che cosa succede a quel cliente in customers LEFT JOIN orders?
- Il cliente compare una volta per ogni ordine presente nella tabella
- Il cliente compare una volta, con NULL nelle colonne dell’ordine
- Il cliente viene escluso dal risultato
- La query fallisce con un errore
Risposta: Il cliente compare una volta, con NULL nelle colonne dell’ordine. Un LEFT JOIN mantiene ogni riga della tabella di sinistra e riempie con NULL la parte mancante a destra. Escludere il cliente è ciò che fa un INNER JOIN.
4Il metodo passo dopo passo
Per scrivere una query, o per capire che cosa restituisce una query data:
- Trova le tabelle che contengono i dati, e come sono collegate dalle chiavi.
- Scrivi FROM con i join. Scegli LEFT JOIN quando le righe senza corrispondenza devono restare.
- Aggiungi WHERE per le condizioni sulle singole righe.
- Se la domanda dice “per” o “per ciascuno”, aggiungi GROUP BY e l’aggregazione.
- Aggiungi HAVING per le condizioni sull’aggregazione, poi ORDER BY se l’ordine conta.
- Verifica il risultato su un piccolo esempio: elenca le righe dopo ogni clausola, nell’ordine in cui le esegue il database.
Per una domanda teorica, individua prima il concetto (una chiave, un tipo di join, una forma normale, una proprietà ACID), poi scegli l’opzione che corrisponde alla sua definizione.
5Un esempio svolto
Segui ogni passaggio. Prova a prevedere il successivo prima di aprirlo.
Esempio svoltoLa tabella customers ha le righe (1, Ana), (2, Ben) e (3, Cas). La tabella orders ha le righe (id, customer_id) = (10, 1), (11, 1), (12, 2) e (13, 1). Che cosa restituisce questa query? SELECT c.name, COUNT(o.id) FROM customers c LEFT JOIN orders o ON o.customer_id = c.id GROUP BY c.name
1Ogni cliente viene abbinato agli ordini che riportano il suo id. Ana corrisponde agli ordini 10, 11 e 13. Ben corrisponde all’ordine 12.
Cas non ha ordini. Poiché è un LEFT JOIN, Cas resta nel risultato, con NULL per o.id.
2- Ana, 10
- Ana, 11
- Ana, 13
- Ben, 12
- Cas, NULL
Sono 5 righe.
3GROUP BY c.name crea tre gruppi: Ana con 3 righe, Ben con 1 riga e Cas con 1 riga.
4COUNT(o.id) conta solo i valori che non sono NULL. Ana ottiene 3 e Ben ottiene 1.
Cas ha una riga, ma il suo o.id è NULL, quindi Cas ottiene 0.
5Ana, Ben e Cas insieme hanno 3 + 1 + 0 = 4 ordini, quanti sono le righe di orders. Con COUNT(*) invece, Cas otterrebbe erroneamente 1, perché COUNT(*) conta la riga stessa.
Risposta Ana 3, Ben 1, Cas 0.
6Errori comuni
- Usare un’aggregazione in WHERE. Le condizioni su COUNT, SUM o AVG vanno in HAVING.
- Scrivere = NULL. Qualsiasi confronto con NULL è sconosciuto; usa IS NULL o IS NOT NULL.
- Usare un INNER JOIN quando le righe senza corrispondenza devono restare. Usa un LEFT JOIN.
- Dimenticare la condizione del join. Senza ON, ogni riga viene abbinata a ogni riga (un cross join).
- Selezionare una colonna che non è né in GROUP BY né dentro un’aggregazione.
- Confondere DELETE (elimina righe) e DROP TABLE (elimina l’intera tabella).
- Eseguire UPDATE o DELETE senza WHERE. Modifica ogni riga della tabella.
Autoverifica Una tabella ha 10 righe, e la colonna col è NULL in ogni riga. Che cosa restituisce SELECT COUNT(col)?
- 0
- 10
- 1
- NULL
Risposta: 0. COUNT(col) conta solo i valori che non sono NULL, quindi restituisce 0. COUNT(*) conta le righe e restituirebbe 10.
7Come sono fatte le domande d’esame
- Facile: termini e fatti chiave. Che cosa fanno SELECT, WHERE, ORDER BY o DELETE, chiavi primarie ed esterne, che cosa significa NULL.
- Medio: applicare i concetti. La query giusta per un compito, WHERE contro HAVING, join interni contro esterni, le forme normali, ACID.
- Difficile: casi e analisi. Sottoquery, livelli di isolamento e relative anomalie, BCNF, funzioni finestra, indici e prestazioni delle query, SQL injection.
Quando viene data una query, simulala su poche righe nell’ordine FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY. La maggior parte delle trappole emerge entro tre righe.
Impara passo dopo passo nell’appImpara passo dopo passo nell’app