Comandi QL: la SELECT di base

// obiettivi di apprendimento
Scrivere query SELECT complete con clausole WHERE, ORDER BY e LIMIT
Usare operatori di confronto, BETWEEN, IN, LIKE, IS NULL per filtrare le righe
Applicare alias di colonna e tabella e rimuovere i duplicati con DISTINCT
Implementare la paginazione con LIMIT e OFFSET su dataset reali
🎬
Video
Lezione video completa sulla SELECT e i filtri WHERE
Guarda →
📄
Slides
Schema completo degli operatori SQL per la clausola WHERE
Scarica →
⚗️
Lab
Esercizi pratici con database scuola: 20 query da svolgere
GitHub →
🔗
Risorse
Documentazione ufficiale MySQL e SQL Fiddle per esercitarsi online
Vedi →

La struttura completa della SELECT

La SELECT è il comando più usato in SQL: serve a interrogare il database e ottenere un insieme di righe (detto result set). La sua sintassi segue un ordine ben preciso — e quell’ordine non è casuale: rispecchia l’ordine logico in cui il DBMS elabora le clausole.

// sintassi completa
SELECT [DISTINCT] colonna1 [AS alias], colonna2, ...
FROM   tabella [AS alias_tabella]
[WHERE  condizione]
[ORDER BY colonna [ASC | DESC], ...]
[LIMIT  n [OFFSET m]];

Tra parentesi quadre ci sono le clausole opzionali. La sola obbligatoria è la coppia SELECT … FROM ….

Ordine di esecuzione logico

Il DBMS non legge le clausole nell’ordine in cui le scrivi tu. L’ordine di esecuzione logico è:

#ClausolaCosa fa
1FROMIdentifica la tabella (o le tabelle) da cui estrarre le righe
2WHEREFiltra le righe applicando le condizioni
3SELECTSeleziona e calcola le colonne del risultato
4DISTINCTRimuove i duplicati dal result set
5ORDER BYOrdina le righe risultanti
6LIMIT / OFFSETTronca il result set per la paginazione
// perché conta l’ordine logico?

Capire quest’ordine ti evita errori comuni: ad esempio, non puoi usare un alias di colonna definito nella SELECT all’interno della clausola WHERE, perché il DBMS esegue WHERE prima di SELECT e quell’alias non esiste ancora.

La clausola WHERE: filtrare le righe

La clausola WHERE è il cuore delle query di selezione. Contiene una condizione booleana: il DBMS mantiene nel result set solo le righe per cui la condizione è vera.

Operatori di confronto

OperatoreSignificatoEsempio
=Uguale aWHERE cognome = 'Rossi'
<> oppure !=Diverso daWHERE voto <> 18
< > <= >=Confronto numerico / dateWHERE voto >= 27
ANDEntrambe le condizioni vereWHERE voto >= 18 AND corso_id = 3
ORAlmeno una condizione veraWHERE anno = 1 OR anno = 2
NOTNegazioneWHERE NOT superato = TRUE

Operatori speciali SQL

BETWEEN … AND … — seleziona valori in un intervallo inclusivo (funziona con numeri, date e stringhe):

-- studenti con voto tra 24 e 30 inclusi
SELECT * FROM esame WHERE voto BETWEEN 24 AND 30;

-- equivalente esplicito:
SELECT * FROM esame WHERE voto >= 24 AND voto <= 30;

IN (…) — verifica se il valore è contenuto in una lista di valori:

-- corsi del primo o del secondo anno
SELECT * FROM corso WHERE anno IN (1, 2);

-- equivalente OR:
SELECT * FROM corso WHERE anno = 1 OR anno = 2;

LIKE — confronto con pattern su stringhe. Due caratteri speciali:

  • % — qualsiasi sequenza di caratteri (anche vuota)
  • _ — esattamente un carattere
-- cognomi che iniziano con "Ros"
SELECT * FROM studente WHERE cognome LIKE 'Ros%';

-- nomi di esattamente 4 caratteri
SELECT * FROM corso WHERE nome LIKE '____';

-- email di Gmail
SELECT * FROM studente WHERE email LIKE '%@gmail.com';
// attenzione — LIKE e performance

Un pattern che inizia con % (es. '%mario%') non può usare un indice B-tree e provoca una full table scan: su tabelle grandi è molto lento. Usalo con consapevolezza.

IS NULL / IS NOT NULL — in SQL il valore NULL non è uguale a niente, nemmeno a se stesso. Per questo non puoi scrivere WHERE email = NULL: devi usare l’operatore dedicato:

-- studenti senza indirizzo email registrato
SELECT nome, cognome FROM studente WHERE email IS NULL;

-- studenti con email registrata
SELECT nome, cognome FROM studente WHERE email IS NOT NULL;

ORDER BY: ordinare il risultato

ORDER BY ordina il result set secondo uno o più criteri. L’ordine di default è ASC (crescente); va specificato DESC per decrescente.

-- per voto decrescente (dal più alto al più basso)
SELECT studente_id, corso_id, voto
FROM esame
ORDER BY voto DESC;

-- prima per anno del corso, poi per nome corso alfabetico
SELECT nome, anno
FROM corso
ORDER BY anno ASC, nome ASC;
// null nell’ordinamento

I valori NULL vengono messi per ultimi in MySQL (con ASC) e per primi in PostgreSQL. Il comportamento varia tra DBMS.

LIMIT e OFFSET: paginare i risultati

Su tabelle con migliaia di righe, restituire l’intero result set è inefficiente. LIMIT tronca l’output a n righe; OFFSET salta le prime m righe — combinati implementano la paginazione.

-- prima pagina: le prime 10 righe
SELECT * FROM studente ORDER BY cognome LIMIT 10;

-- seconda pagina: righe 11–20 (salta le prime 10)
SELECT * FROM studente ORDER BY cognome LIMIT 10 OFFSET 10;

-- terza pagina
SELECT * FROM studente ORDER BY cognome LIMIT 10 OFFSET 20;

La formula generale per la pagina p con n righe per pagina è OFFSET = (p - 1) * n.

DISTINCT: eliminare i duplicati

SELECT DISTINCT rimuove le righe duplicate dal result set dopo che le colonne sono state selezionate. È utile quando vuoi ottenere i valori unici di una colonna:

-- lista degli anni in cui sono presenti esami
SELECT DISTINCT anno FROM esame_storico ORDER BY anno;

-- combinazioni uniche corso–anno
SELECT DISTINCT corso_id, anno_accademico FROM iscrizione;

Alias: rinominare colonne e tabelle

La parola chiave AS permette di assegnare un nome temporaneo a una colonna o a una tabella nel context della query. È puramente cosmetico per le colonne, ma diventa necessario per le tabelle quando fai i JOIN (prossima lezione).

-- alias di colonna per rendere l'output più leggibile
SELECT
  nome        AS "Nome studente",
  cognome     AS "Cognome",
  data_nascita AS "Data di nascita"
FROM studente;

-- alias su espressione calcolata
SELECT
  nome,
  (crediti * 3) AS ore_totali
FROM corso;

Esempi pratici: database scuola

Usiamo il database costruito nelle lezioni precedenti (tabelle STUDENTE, CORSO, ESAME).

Query progressivamente più complesse

-- 1. Tutti gli studenti, ordinati per cognome
SELECT nome, cognome FROM studente ORDER BY cognome ASC;

-- 2. Studenti nati dopo il 2005
SELECT nome, cognome, data_nascita
FROM studente
WHERE data_nascita > '2005-12-31'
ORDER BY data_nascita;

-- 3. Esami superati con lode (voto = 31)
SELECT studente_id, corso_id, data_esame
FROM esame
WHERE voto = 31;

-- 4. Corsi del primo anno con meno di 6 crediti
SELECT nome, crediti
FROM corso
WHERE anno = 1 AND crediti < 6
ORDER BY crediti;

-- 5. Studenti il cui cognome contiene "ri"
SELECT nome, cognome
FROM studente
WHERE cognome LIKE '%ri%';

-- 6. Esami con voto tra 27 e 30, pagina 1 (10 risultati)
SELECT studente_id, corso_id, voto
FROM esame
WHERE voto BETWEEN 27 AND 30
ORDER BY voto DESC
LIMIT 10;

-- 7. Lista distinta degli anni in cui esistono corsi
SELECT DISTINCT anno AS "Anno di corso"
FROM corso
ORDER BY anno;
📌 Riepilogo — Punti chiave
  • La SELECT segue la sintassi: SELECT … FROM … [WHERE] [ORDER BY] [LIMIT]
  • L’ordine di esecuzione logico è FROM → WHERE → SELECT → DISTINCT → ORDER BY → LIMIT
  • BETWEEN, IN, LIKE e IS NULL sono shortcut potenti per condizioni comuni nella WHERE
  • LIKE '%testo%' esegue full scan: lento su tabelle grandi; LIKE 'testo%' può usare un indice
  • NULL non si confronta con =: usa sempre IS NULL / IS NOT NULL
  • LIMIT n OFFSET m implementa la paginazione: formula OFFSET = (pagina - 1) × n
  • Gli alias (AS) rinominano colonne nell’output e diventano obbligatori nei JOIN

Lascia un commento