Salta ai contenuti
Manuale LogoManuale Logo

Esercizi SQL

Dalla tabella clienti, mostrare tutte le colonne di tutte le righe.

Soluzione spiegata

In questo primo esercizio basta leggere l’intera tabella con SELECT *.

SELECT *
FROM clienti;

La query non filtra nulla e chiede al database di restituire tutti i dati presenti in clienti.

Dalla tabella clienti (id, nome, email), mostrare solo nome ed email.

Soluzione spiegata

Qui non usiamo *, ma indichiamo solo le colonne che ci servono.

SELECT nome, email
FROM clienti;

Il risultato contiene solo i dati utili alla richiesta e resta piu facile da leggere.

Dalla tabella prodotti (id, nome, prezzo), mostrare nome con l’alias prodotto e prezzo con l’alias costo.

Soluzione spiegata

Gli alias aiutano a rendere il risultato piu chiaro senza cambiare i dati.

SELECT nome AS prodotto, prezzo AS costo
FROM prodotti;

AS assegna un nome temporaneo alle colonne nel risultato finale.

Dalla tabella clienti (id, nome, citta), mostrare i clienti che hanno Roma nella colonna citta.

Soluzione spiegata

Usiamo WHERE per tenere solo le righe che rispettano la condizione.

SELECT id, nome, citta
FROM clienti
WHERE citta = 'Roma';

La query controlla la colonna citta riga per riga e tiene solo i clienti di Roma.

Dalla tabella ordini (id, totale), mostrare gli ordini con totale maggiore di 100.

Soluzione spiegata

In questo caso il filtro riguarda un numero, quindi non usiamo apici.

SELECT id, totale
FROM ordini
WHERE totale > 100;

Restano nel risultato solo le righe in cui totale supera 100.

Dalla tabella prodotti (nome, prezzo), mostrare i prodotti con prezzo minore o uguale a 20.

Soluzione spiegata

L’operatore <= serve quando vuoi includere anche il valore di confine.

SELECT nome, prezzo
FROM prodotti
WHERE prezzo <= 20;

La query mostra i prodotti economici, compresi quelli che costano esattamente 20.

Dalla tabella clienti (nome, citta, attivo), mostrare i clienti di Roma che risultano attivi.

Soluzione spiegata

Con AND chiediamo che entrambe le condizioni siano vere.

SELECT nome, citta, attivo
FROM clienti
WHERE citta = 'Roma' AND attivo = TRUE;

La riga entra nel risultato solo se il cliente e sia di Roma sia attivo.

Dalla tabella clienti (nome, citta), mostrare i clienti che vivono a Roma oppure a Milano.

Soluzione spiegata

Con OR basta che almeno una delle due condizioni sia vera.

SELECT nome, citta
FROM clienti
WHERE citta = 'Roma' OR citta = 'Milano';

La query raccoglie i clienti di entrambe le citta in un unico risultato.

Dalla tabella clienti (nome, attivo), mostrare i clienti che non sono attivi.

Soluzione spiegata

NOT ribalta la condizione che segue.

SELECT nome, attivo
FROM clienti
WHERE NOT attivo;

Il risultato contiene solo le righe in cui attivo non risulta vero.

Dalla tabella clienti (id, nome), mostrare i nomi in ordine alfabetico crescente.

Soluzione spiegata

Per ordinare i risultati usiamo ORDER BY con ASC.

SELECT id, nome
FROM clienti
ORDER BY nome ASC;

ASC ordina dal valore piu piccolo al piu grande, quindi nel caso dei testi in ordine alfabetico.

Dalla tabella prodotti (nome, prezzo), mostrare i prodotti dal prezzo piu alto al piu basso.

Soluzione spiegata

Per avere prima i valori piu grandi usiamo DESC.

SELECT nome, prezzo
FROM prodotti
ORDER BY prezzo DESC;

La query e utile quando vuoi vedere subito gli elementi piu costosi.

Dalla tabella ordini (id, data_ordine), mostrare solo le prime 5 righe del risultato.

Soluzione spiegata

LIMIT restringe il numero di righe restituite.

SELECT id, data_ordine
FROM ordini
LIMIT 5;

Il database interrompe il risultato dopo cinque righe.

Dalla tabella ordini (id, data_ordine), saltare le prime 5 righe e mostrare le successive 5.

Soluzione spiegata

Qui combiniamo LIMIT e OFFSET.

SELECT id, data_ordine
FROM ordini
LIMIT 5 OFFSET 5;

OFFSET 5 salta le prime cinque righe del risultato, poi LIMIT 5 ne prende altre cinque.

Dalla tabella clienti (nome, email), mostrare i clienti che non hanno email salvata.

Soluzione spiegata

Con NULL non si usa =, ma IS NULL.

SELECT nome, email
FROM clienti
WHERE email IS NULL;

La query cerca proprio l’assenza del dato, non un testo vuoto.

Dalla tabella clienti (nome, email), mostrare i clienti che hanno un’email presente.

Soluzione spiegata

Il contrario di IS NULL e IS NOT NULL.

SELECT nome, email
FROM clienti
WHERE email IS NOT NULL;

Restano solo le righe in cui la colonna email contiene un valore.

Nella tabella clienti (id, nome, email), inserire un nuovo cliente con nome Luca ed email luca@email.it.

Soluzione spiegata

Con INSERT INTO aggiungiamo una nuova riga indicando chiaramente le colonne.

INSERT INTO clienti (nome, email)
VALUES ('Luca', 'luca@email.it');

Il primo valore va nella colonna nome, il secondo nella colonna email.

Nella tabella prodotti (nome, prezzo), inserire due righe: Mouse a 19.90 e Tastiera a 49.90.

Soluzione spiegata

Un solo INSERT puo aggiungere piu righe.

INSERT INTO prodotti (nome, prezzo)
VALUES
('Mouse', 19.90),
('Tastiera', 49.90);

Ogni gruppo di valori tra parentesi crea una riga nuova nella tabella.

Nella tabella clienti, aggiornare la citta del cliente con id = 3 impostandola a Bologna.

Soluzione spiegata

UPDATE modifica una riga esistente, mentre WHERE sceglie quale.

UPDATE clienti
SET citta = 'Bologna'
WHERE id = 3;

Senza WHERE, la query modificherebbe la citta di tutte le righe.

Nella tabella prodotti, aumentare del 10% il prezzo del prodotto con id = 5.

Soluzione spiegata

Il nuovo valore puo dipendere da quello gia presente nella colonna.

UPDATE prodotti
SET prezzo = prezzo * 1.10
WHERE id = 5;

La formula prende il prezzo attuale e lo moltiplica per 1.10.

Nella tabella clienti, eliminare la riga con id = 8.

Soluzione spiegata

Per cancellare una sola riga usiamo DELETE con un filtro preciso.

DELETE FROM clienti
WHERE id = 8;

Il filtro evita di cancellare piu righe del necessario.

Dalla tabella ordini, contare quante righe ci sono.

Soluzione spiegata

COUNT(*) restituisce il numero totale di righe.

SELECT COUNT(*) AS numero_ordini
FROM ordini;

L’alias rende piu leggibile il nome della colonna nel risultato.

Dalla tabella ordini (totale), calcolare la somma di tutti i totali.

Soluzione spiegata

Per sommare molti valori numerici usiamo SUM().

SELECT SUM(totale) AS incasso_totale
FROM ordini;

La query restituisce un solo valore riassuntivo con l’incasso complessivo.

Dalla tabella prodotti (prezzo), calcolare il prezzo medio.

Soluzione spiegata

AVG() e la funzione che calcola la media aritmetica.

SELECT AVG(prezzo) AS prezzo_medio
FROM prodotti;

Il risultato e un solo numero che rappresenta il prezzo medio dei prodotti.

Dalla tabella prodotti (prezzo), trovare il prezzo piu basso e il prezzo piu alto.

Soluzione spiegata

MIN() trova il valore piu piccolo, mentre MAX() trova il piu grande.

SELECT MIN(prezzo) AS prezzo_minimo, MAX(prezzo) AS prezzo_massimo
FROM prodotti;

In una sola query otteniamo entrambi gli estremi del catalogo.

Dalla tabella clienti (citta), contare quanti clienti ci sono per ogni citta.

Soluzione spiegata

Con GROUP BY creiamo un gruppo per ogni citta, poi COUNT(*) conta le righe del gruppo.

SELECT citta, COUNT(*) AS numero_clienti
FROM clienti
GROUP BY citta;

La query restituisce una riga per ogni citta presente nella tabella.

Dalla tabella ordini (cliente_id, totale), calcolare il totale speso da ogni cliente.

Soluzione spiegata

Qui raggruppiamo per cliente e sommiamo il totale degli ordini del gruppo.

SELECT cliente_id, SUM(totale) AS totale_speso
FROM ordini
GROUP BY cliente_id;

Ogni riga del risultato rappresenta un cliente con la somma dei suoi ordini.

Dalla tabella ordini (cliente_id, totale), mostrare solo i clienti che hanno almeno 2 ordini.

Soluzione spiegata

Prima creiamo i gruppi con GROUP BY, poi filtriamo i gruppi con HAVING.

SELECT cliente_id, COUNT(*) AS numero_ordini
FROM ordini
GROUP BY cliente_id
HAVING COUNT(*) >= 2;

HAVING lavora sul risultato aggregato, non sulle singole righe iniziali.

Dalla tabella prodotti (categoria, prezzo), mostrare le categorie con prezzo medio superiore a 50.

Soluzione spiegata

Anche qui il filtro riguarda una media di gruppo, quindi serve HAVING.

SELECT categoria, AVG(prezzo) AS prezzo_medio
FROM prodotti
GROUP BY categoria
HAVING AVG(prezzo) > 50;

Il database calcola la media per categoria e poi tiene solo i gruppi sopra 50.

Dalle tabelle clienti (id, nome) e ordini (id, cliente_id, totale), mostrare nome del cliente e totale dell’ordine usando una INNER JOIN.

Soluzione spiegata

INNER JOIN collega solo le righe che trovano una corrispondenza in entrambe le tabelle.

SELECT clienti.nome, ordini.totale
FROM clienti
INNER JOIN ordini ON clienti.id = ordini.cliente_id;

La condizione dopo ON spiega come abbinare clienti e ordini.

Dalle tabelle clienti (id, nome) e ordini (cliente_id, totale), mostrare tutti i clienti anche se non hanno ordini.

Soluzione spiegata

Per tenere tutte le righe della tabella di sinistra usiamo LEFT JOIN.

SELECT clienti.nome, ordini.totale
FROM clienti
LEFT JOIN ordini ON clienti.id = ordini.cliente_id;

Se un cliente non ha ordini, nelle colonne di ordini comparira NULL.

Dalle tabelle clienti (id, nome, citta) e ordini (cliente_id, totale), mostrare nome e totale degli ordini dei clienti di Roma.

Soluzione spiegata

Combiniamo una JOIN con un filtro WHERE.

SELECT clienti.nome, ordini.totale
FROM clienti
INNER JOIN ordini ON clienti.id = ordini.cliente_id
WHERE clienti.citta = 'Roma';

Prima colleghiamo le tabelle, poi teniamo solo le righe dei clienti di Roma.

Dalle tabelle clienti (id, nome) e ordini (cliente_id, totale), mostrare i nomi dei clienti con alias di tabella c e i totali con alias di tabella o.

Soluzione spiegata

Gli alias corti rendono la query piu compatta nelle join.

SELECT c.nome, o.totale
FROM clienti AS c
INNER JOIN ordini AS o ON c.id = o.cliente_id;

c e o sono solo soprannomi temporanei usati dentro questa query.

Dalla tabella ordini (id, totale), mostrare i 3 ordini con totale piu alto.

Soluzione spiegata

Prima ordiniamo in modo decrescente, poi limitiamo il risultato.

SELECT id, totale
FROM ordini
ORDER BY totale DESC
LIMIT 3;

Senza ORDER BY, le tre righe mostrate non sarebbero necessariamente quelle con totale piu alto.

Dalla tabella prodotti (nome, prezzo), mostrare i prodotti con prezzo compreso tra 10 e 50, ordinati dal prezzo piu basso al piu alto.

Soluzione spiegata

Usiamo due condizioni numeriche e poi ordiniamo il risultato.

SELECT nome, prezzo
FROM prodotti
WHERE prezzo >= 10 AND prezzo <= 50
ORDER BY prezzo ASC;

La query tiene solo i prodotti nel range richiesto e li dispone in ordine crescente.

Dalla tabella clienti (nome, citta, attivo), contare quanti clienti attivi ci sono per ogni citta.

Soluzione spiegata

Prima filtriamo i clienti attivi, poi raggruppiamo per citta.

SELECT citta, COUNT(*) AS clienti_attivi
FROM clienti
WHERE attivo = TRUE
GROUP BY citta;

WHERE agisce prima del raggruppamento e lascia solo le righe utili al conteggio.

Dalla tabella ordini (cliente_id, totale), mostrare i clienti con una spesa totale superiore a 200, ordinando dal totale piu alto al piu basso.

Soluzione spiegata

Serve una somma per cliente, un filtro sul gruppo e un ordinamento finale.

SELECT cliente_id, SUM(totale) AS totale_speso
FROM ordini
GROUP BY cliente_id
HAVING SUM(totale) > 200
ORDER BY totale_speso DESC;

La query produce prima i totali per cliente, poi tiene solo quelli sopra 200 e li ordina.

Dalla tabella prodotti (nome, prezzo), mostrare i prodotti con prezzo superiore alla media dei prezzi.

Soluzione spiegata

La media viene calcolata in una subquery e confrontata nella query esterna.

SELECT nome, prezzo
FROM prodotti
WHERE prezzo > (
SELECT AVG(prezzo)
FROM prodotti
);

La query interna produce un solo valore, che la query esterna usa come soglia.

Dalla tabella clienti (id, nome) e dalla tabella ordini (cliente_id), mostrare i clienti che hanno fatto almeno un ordine.

Soluzione spiegata

Possiamo usare una subquery con IN per confrontare l’id del cliente con la lista dei cliente_id.

SELECT nome
FROM clienti
WHERE id IN (
SELECT cliente_id
FROM ordini
);

La subquery costruisce la lista degli id presenti negli ordini, poi la query esterna trova i nomi corrispondenti.

Dalla tabella clienti (id, nome) e dalla tabella ordini (cliente_id, totale), mostrare i clienti che hanno almeno un ordine con totale maggiore di 100.

Soluzione spiegata

La subquery restringe prima gli ordini, poi la query esterna recupera i clienti giusti.

SELECT nome
FROM clienti
WHERE id IN (
SELECT cliente_id
FROM ordini
WHERE totale > 100
);

La soluzione segue un ragionamento in due passaggi molto naturale.

Creare una CTE con nome ordini_grandi che contenga gli ordini con totale > 100, poi mostrare id, cliente_id e totale.

Soluzione spiegata

Con WITH diamo un nome chiaro al risultato intermedio.

WITH ordini_grandi AS (
SELECT id, cliente_id, totale
FROM ordini
WHERE totale > 100
)
SELECT id, cliente_id, totale
FROM ordini_grandi;

La CTE rende il passaggio intermedio esplicito e piu leggibile di una query annidata.

Creare una CTE ordini_grandi con gli ordini sopra 100, poi mostrare il nome del cliente e il totale dell’ordine.

Soluzione spiegata

La CTE prepara i dati; la query principale li collega ai clienti.

WITH ordini_grandi AS (
SELECT id, cliente_id, totale
FROM ordini
WHERE totale > 100
)
SELECT clienti.nome, ordini_grandi.totale
FROM ordini_grandi
INNER JOIN clienti ON clienti.id = ordini_grandi.cliente_id;

Separare i due passaggi aiuta a leggere la query come una piccola sequenza logica.

Dalla tabella ordini (id, data_ordine, totale), mostrare gli ordini dal piu recente al piu vecchio.

Soluzione spiegata

Per avere prima le date piu nuove ordiniamo in modo decrescente.

SELECT id, data_ordine, totale
FROM ordini
ORDER BY data_ordine DESC;

Questo ordinamento e molto comune quando si consultano cronologie o liste di attivita.

Dalla tabella ordini (id, data_ordine, totale), mostrare i 10 ordini piu recenti.

Soluzione spiegata

Uniamo ordinamento per data e limitazione delle righe.

SELECT id, data_ordine, totale
FROM ordini
ORDER BY data_ordine DESC
LIMIT 10;

Prima decidiamo quali righe vengono per prime, poi ne prendiamo solo dieci.

Dalla tabella clienti (id, nome) e dalla tabella ordini (cliente_id), mostrare i clienti che non hanno ordini.

Soluzione spiegata

Con LEFT JOIN teniamo tutti i clienti e poi cerchiamo quelli senza corrispondenza.

SELECT clienti.nome
FROM clienti
LEFT JOIN ordini ON clienti.id = ordini.cliente_id
WHERE ordini.cliente_id IS NULL;

Se la join non trova ordini, le colonne della tabella ordini diventano NULL.

Dalla tabella clienti (id, nome, email), contare quante email risultano presenti.

Soluzione spiegata

COUNT(email) conta solo le righe in cui email non e NULL.

SELECT COUNT(email) AS email_presenti
FROM clienti;

Questo esercizio mostra la differenza tra contare le righe e contare i valori effettivamente presenti in una colonna.

Dalla tabella clienti (citta, attivo), mostrare le citta con almeno 3 clienti attivi.

Soluzione spiegata

Filtriamo prima i clienti attivi e poi usiamo HAVING sul conteggio per citta.

SELECT citta, COUNT(*) AS numero_clienti_attivi
FROM clienti
WHERE attivo = TRUE
GROUP BY citta
HAVING COUNT(*) >= 3;

La query combina il filtro sulle righe con il filtro finale sui gruppi.

Dalla tabella prodotti (categoria, prezzo), mostrare per ogni categoria il numero di prodotti e il prezzo medio.

Soluzione spiegata

Possiamo calcolare piu valori aggregati nello stesso raggruppamento.

SELECT categoria, COUNT(*) AS numero_prodotti, AVG(prezzo) AS prezzo_medio
FROM prodotti
GROUP BY categoria;

Ogni riga del risultato riassume una categoria con due informazioni diverse.

Dalle tabelle clienti (id, nome) e ordini (cliente_id, totale), mostrare il totale speso da ogni cliente con il relativo nome.

Soluzione spiegata

Qui una JOIN porta il nome del cliente, mentre SUM() calcola la spesa complessiva.

SELECT clienti.id, clienti.nome, SUM(ordini.totale) AS totale_speso
FROM clienti
INNER JOIN ordini ON clienti.id = ordini.cliente_id
GROUP BY clienti.id, clienti.nome;

La query unisce i dati delle due tabelle e poi riassume gli ordini per cliente.

Dalle tabelle clienti (id, nome, attivo) e ordini (cliente_id, totale), mostrare il totale speso solo dai clienti attivi.

Soluzione spiegata

Filtriamo i clienti attivi e poi raggruppiamo i loro ordini.

SELECT clienti.id, clienti.nome, SUM(ordini.totale) AS totale_speso
FROM clienti
INNER JOIN ordini ON clienti.id = ordini.cliente_id
WHERE clienti.attivo = TRUE
GROUP BY clienti.id, clienti.nome;

Il filtro WHERE entra in gioco prima della somma finale.

Creare una CTE totali_clienti che calcoli la spesa totale per ogni cliente, poi mostrare solo i clienti con totale superiore a 200.

Soluzione spiegata

La CTE separa il calcolo dei totali dal filtro finale, rendendo la query piu leggibile.

WITH totali_clienti AS (
SELECT cliente_id, SUM(totale) AS totale_speso
FROM ordini
GROUP BY cliente_id
)
SELECT cliente_id, totale_speso
FROM totali_clienti
WHERE totale_speso > 200;

Prima costruiamo il riepilogo per cliente, poi lavoriamo su quel risultato come se fosse una tabella temporanea.