In questa lezione impari a
- tradurre uno schema logico in CREATE TABLE con i vincoli giusti
- popolare un database con INSERT
- scrivere query con JOIN, raggruppamenti e sottoquery su casi sempre nuovi
- controllare da soli se una query è giusta confrontando il risultato
Questa è la palestra del corso: otto casi nuovi, piccoli e completi, su cui ripetere tutto il percorso delle lezioni 1–6. Si possono fare dopo la lezione 6, anche in parallelo con le lezioni di PHP; l'ultima è una mini-traccia nello stile dell'Esame di Stato.
Ogni esercitazione ha sempre la stessa struttura:
- il testo del caso e lo schema logico già pronto (la chiave primaria è sottolineata, le chiavi esterne sono in corsivo con l'asterisco);
- i dati da inserire;
- le query da scrivere, con i risultati attesi per controllarti.
Lavora in phpMyAdmin o nella console SQL di XAMPP. Conviene scrivere tutto in un file .sql in Visual Studio Code e poi importarlo: se sbagli, correggi e reimporti. Per ripartire da zero, comincia il file con:
DROP DATABASE IF EXISTS es_rubrica;
CREATE DATABASE es_rubrica CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE es_rubrica;
Come controllarti. Sotto ogni esercitazione trovi Controlla i risultati: sono le righe che una query giusta deve restituire. Se le tue righe sono le stesse, la query va bene, anche se l'hai scritta in modo diverso. Le soluzioni complete le ha il docente.
Esercitazione 1 – La rubrica
⭐ Facile · CREATE TABLE, INSERT, SELECT con WHERE, ORDER BY e LIKE
Una rubrica telefonica salva i contatti di una classe: nome, cognome, telefono (che non può ripetersi), email (facoltativa), città e data di nascita.
Lo schema logico
contatti (id, nome, cognome, telefono, email, citta, data_nascita)
I dati da inserire
contatti
| nome | cognome | telefono | citta | data_nascita | |
|---|---|---|---|---|---|
| Marco | Rossi | 3331234567 | marco.rossi@mail.it | Torino | 2008-03-12 |
| Giulia | Bianchi | 3409876543 | vuoto | Milano | 2007-11-02 |
| Luca | Bruno | 3475551122 | luca.b@mail.it | Torino | 2008-03-28 |
| Sara | Verdi | 3201112233 | sara.verdi@mail.it | Moncalieri | 2008-07-19 |
| Andrea | Bassi | 3389990001 | vuoto | Torino | 2007-12-05 |
| Elena | Ferrari | 3354443322 | elena.f@mail.it | Milano | 2008-05-30 |
Cosa fare
-
Crea il database
es_rubricae scrivi leCREATE TABLE, scegliendo i tipi e i vincoli giusti: chiavi primarie,NOT NULL,UNIQUEeCHECKdove servono, chiavi esterne. -
Inserisci i dati con le
INSERT. -
Scrivi le query:
- Cognome, nome e telefono di tutti i contatti, in ordine alfabetico di cognome e nome.
- I contatti che abitano a Torino.
- I contatti che non hanno l'email.
- I contatti il cui cognome inizia con la lettera B.
- Chi compie gli anni a marzo (suggerimento: la funzione
MONTH). - Quanti contatti ci sono in ogni città.
Da pensare
- Giulia Bianchi ha finalmente un'email:
giulia.bianchi@mail.it. Aggiorna il suo contatto e controlla con una SELECT. - Prova a inserire un nuovo contatto con lo stesso telefono di Marco Rossi. Che cosa succede? Perché?
Controlla i risultati
Se le tue query restituiscono queste righe, sono giuste (l'ordine delle colonne e i loro nomi possono essere diversi).
Query 1 – 6 righe
| cognome | nome | telefono |
|---|---|---|
| Bassi | Andrea | 3389990001 |
| Bianchi | Giulia | 3409876543 |
| Bruno | Luca | 3475551122 |
| Ferrari | Elena | 3354443322 |
| Rossi | Marco | 3331234567 |
| Verdi | Sara | 3201112233 |
Query 2 – 3 righe
| nome | cognome |
|---|---|
| Marco | Rossi |
| Luca | Bruno |
| Andrea | Bassi |
Query 3 – 2 righe
| nome | cognome |
|---|---|
| Giulia | Bianchi |
| Andrea | Bassi |
Query 4 – 3 righe
| nome | cognome |
|---|---|
| Giulia | Bianchi |
| Luca | Bruno |
| Andrea | Bassi |
Query 5 – 2 righe
| nome | cognome | data_nascita |
|---|---|---|
| Marco | Rossi | 2008-03-12 |
| Luca | Bruno | 2008-03-28 |
Query 6 – 3 righe
| citta | contatti |
|---|---|
| Torino | 3 |
| Milano | 2 |
| Moncalieri | 1 |
Esercitazione 2 – La videoteca
⭐ Facile · chiave esterna, JOIN tra due tabelle, LEFT JOIN, AVG e COUNT
Una videoteca registra i film e i loro registi. Ogni film ha un solo regista; un regista può aver girato più film, oppure nessuno di quelli presenti in archivio.
Lo schema logico
registi (id, nome, cognome, nazionalita) film (id, titolo, anno, durata, genere, regista_id*) regista_id → registi(id)
I dati da inserire
registi
| id | nome | cognome | nazionalita |
|---|---|---|---|
| 1 | Federico | Fellini | italiana |
| 2 | Christopher | Nolan | britannica |
| 3 | Hayao | Miyazaki | giapponese |
| 4 | Paola | Cortellesi | italiana |
| 5 | Steven | Spielberg | statunitense |
film
| id | titolo | anno | durata | genere | regista_id |
|---|---|---|---|---|---|
| 1 | La dolce vita | 1960 | 174 | Drammatico | 1 |
| 2 | 8½ | 1963 | 138 | Drammatico | 1 |
| 3 | Inception | 2010 | 148 | Fantascienza | 2 |
| 4 | Interstellar | 2014 | 169 | Fantascienza | 2 |
| 5 | Oppenheimer | 2023 | 180 | Biografico | 2 |
| 6 | La città incantata | 2001 | 125 | Animazione | 3 |
| 7 | Il mio vicino Totoro | 1988 | 86 | Animazione | 3 |
| 8 | C'è ancora domani | 2023 | 118 | Drammatico | 4 |
Cosa fare
-
Crea il database
es_videotecae scrivi leCREATE TABLE, scegliendo i tipi e i vincoli giusti: chiavi primarie,NOT NULL,UNIQUEeCHECKdove servono, chiavi esterne. -
Inserisci i dati con le
INSERT. -
Scrivi le query:
- Titolo, anno, nome e cognome del regista di tutti i film, dal più recente (a parità di anno, per titolo).
- I film girati da registi italiani.
- I film usciti dal 2000 in poi che durano più di due ore e mezza.
- La durata media dei film per ogni genere, arrotondata al minuto.
- Quanti film ha girato ogni regista, compresi quelli che in archivio non ne hanno nessuno.
- Il film più lungo, con il suo regista (usa una sottoquery con
MAX).
Da pensare
- Prova a cancellare il regista Christopher Nolan. Che cosa succede? Come si potrebbe fare se si volessero cancellare anche i suoi film?
Controlla i risultati
Se le tue query restituiscono queste righe, sono giuste (l'ordine delle colonne e i loro nomi possono essere diversi).
Query 1 – 8 righe
| titolo | anno | nome | cognome |
|---|---|---|---|
| C'è ancora domani | 2023 | Paola | Cortellesi |
| Oppenheimer | 2023 | Christopher | Nolan |
| Interstellar | 2014 | Christopher | Nolan |
| Inception | 2010 | Christopher | Nolan |
| La città incantata | 2001 | Hayao | Miyazaki |
| Il mio vicino Totoro | 1988 | Hayao | Miyazaki |
| 8½ | 1963 | Federico | Fellini |
| La dolce vita | 1960 | Federico | Fellini |
Query 2 – 3 righe
| titolo | cognome |
|---|---|
| La dolce vita | Fellini |
| 8½ | Fellini |
| C'è ancora domani | Cortellesi |
Query 3 – 2 righe
| titolo | anno | durata |
|---|---|---|
| Interstellar | 2014 | 169 |
| Oppenheimer | 2023 | 180 |
Query 4 – 4 righe
| genere | durata_media |
|---|---|
| Animazione | 106 |
| Biografico | 180 |
| Drammatico | 143 |
| Fantascienza | 159 |
Query 5 – 5 righe
| cognome | film |
|---|---|
| Nolan | 3 |
| Fellini | 2 |
| Miyazaki | 2 |
| Cortellesi | 1 |
| Spielberg | 0 |
Query 6 – 1 riga
| titolo | durata | cognome |
|---|---|---|
| Oppenheimer | 180 | Nolan |
Esercitazione 3 – La palestra
⭐⭐ Medio · relazione N:M con tabella ponte, LEFT JOIN, HAVING
Una palestra offre dei corsi, ciascuno in un giorno e a un'ora fissi e con un numero massimo di posti. Ogni iscritto può frequentare più corsi e ogni corso ha più iscritti: per ogni iscrizione si registra la data.
Lo schema logico
corsi (id, nome, giorno, ora, posti) iscritti (id, nome, cognome, data_nascita) iscrizioni (iscritto_id*, corso_id*, data_iscrizione) iscritto_id → iscritti(id), corso_id → corsi(id)
I dati da inserire
corsi
| id | nome | giorno | ora | posti |
|---|---|---|---|---|
| 1 | Yoga | lunedì | 18:00 | 10 |
| 2 | Pilates | martedì | 19:00 | 8 |
| 3 | Spinning | mercoledì | 18:30 | 3 |
| 4 | Zumba | giovedì | 20:00 | 12 |
| 5 | Boxe | venerdì | 19:30 | 6 |
iscritti
| id | nome | cognome | data_nascita |
|---|---|---|---|
| 1 | Anna | Neri | 1995-04-10 |
| 2 | Paolo | Galli | 1988-09-21 |
| 3 | Chiara | Costa | 2001-01-15 |
| 4 | Davide | Ricci | 1979-06-02 |
| 5 | Marta | Fontana | 1999-12-30 |
| 6 | Simone | Greco | 2003-08-08 |
iscrizioni
| iscritto_id | corso_id | data_iscrizione |
|---|---|---|
| 1 | 1 | 2026-09-01 |
| 1 | 2 | 2026-09-01 |
| 2 | 3 | 2026-09-03 |
| 3 | 3 | 2026-09-05 |
| 4 | 3 | 2026-09-05 |
| 3 | 1 | 2026-09-06 |
| 5 | 4 | 2026-09-10 |
| 6 | 4 | 2026-09-12 |
| 1 | 4 | 2026-09-15 |
Cosa fare
-
Crea il database
es_palestrae scrivi leCREATE TABLE, scegliendo i tipi e i vincoli giusti: chiavi primarie,NOT NULL,UNIQUEeCHECKdove servono, chiavi esterne. -
Inserisci i dati con le
INSERT. -
Scrivi le query:
- Nome e cognome degli iscritti al corso di Spinning.
- Per ogni corso, il numero di iscritti (anche zero).
- I corsi che non hanno nemmeno un iscritto.
- Per ogni corso, i posti ancora liberi.
- Gli iscritti che frequentano più di un corso, con il numero di corsi.
- I corsi frequentati da Anna Neri, con giorno e ora, in ordine di nome del corso.
Da pensare
- Il corso di Spinning è pieno. Il database impedisce di aggiungere un quarto iscritto? Se no, dove andrebbe fatto il controllo?
Controlla i risultati
Se le tue query restituiscono queste righe, sono giuste (l'ordine delle colonne e i loro nomi possono essere diversi).
Query 1 – 3 righe
| nome | cognome |
|---|---|
| Chiara | Costa |
| Paolo | Galli |
| Davide | Ricci |
Query 2 – 5 righe
| nome | iscritti |
|---|---|
| Yoga | 2 |
| Pilates | 1 |
| Spinning | 3 |
| Zumba | 3 |
| Boxe | 0 |
Query 3 – 1 riga
| nome |
|---|
| Boxe |
Query 4 – 5 righe
| nome | posti_liberi |
|---|---|
| Yoga | 8 |
| Pilates | 7 |
| Spinning | 0 |
| Zumba | 9 |
| Boxe | 6 |
Query 5 – 2 righe
| nome | cognome | corsi |
|---|---|---|
| Anna | Neri | 3 |
| Chiara | Costa | 2 |
Query 6 – 3 righe
| nome | giorno | ora |
|---|---|---|
| Pilates | martedì | 19:00:00 |
| Yoga | lunedì | 18:00:00 |
| Zumba | giovedì | 20:00:00 |
Esercitazione 4 – L'officina
⭐⭐ Medio · JOIN su tre tabelle, SUM, BETWEEN, sottoquery, chiave primaria non numerica
Un'officina meccanica tiene traccia dei clienti, delle loro auto (identificate dalla targa) e degli interventi eseguiti su ciascuna auto, con data, descrizione e costo.
Lo schema logico
clienti (id, nome, cognome, telefono) auto (targa, marca, modello, anno, cliente_id*) cliente_id → clienti(id) interventi (id, targa*, data, descrizione, costo) targa → auto(targa)
I dati da inserire
clienti
| id | nome | cognome | telefono |
|---|---|---|---|
| 1 | Mario | Esposito | 3311112222 |
| 2 | Laura | Conti | 3322223333 |
| 3 | Giorgio | Marino | 3333334444 |
| 4 | Francesca | Villa | 3344445555 |
auto
| targa | marca | modello | anno | cliente_id |
|---|---|---|---|---|
| AB123CD | Fiat | Panda | 2015 | 1 |
| EF456GH | Fiat | 500 | 2019 | 1 |
| IJ789KL | Volkswagen | Golf | 2017 | 2 |
| MN012OP | Toyota | Yaris | 2021 | 3 |
| QR345ST | Renault | Clio | 2012 | 4 |
interventi
| id | targa | data | descrizione | costo |
|---|---|---|---|---|
| 1 | AB123CD | 2026-01-15 | Tagliando | 180,00 |
| 2 | AB123CD | 2026-06-20 | Cambio pneumatici | 320,00 |
| 3 | IJ789KL | 2026-02-10 | Sostituzione frizione | 850,00 |
| 4 | IJ789KL | 2026-09-05 | Tagliando | 210,00 |
| 5 | QR345ST | 2026-03-18 | Revisione | 79,00 |
| 6 | QR345ST | 2026-04-02 | Sostituzione batteria | 145,00 |
| 7 | EF456GH | 2026-10-01 | Tagliando | 195,00 |
Cosa fare
-
Crea il database
es_officinae scrivi leCREATE TABLE, scegliendo i tipi e i vincoli giusti: chiavi primarie,NOT NULL,UNIQUEeCHECKdove servono, chiavi esterne. -
Inserisci i dati con le
INSERT. -
Scrivi le query:
- Gli interventi sulle auto di Mario Esposito: targa, modello, data, descrizione e costo, in ordine di data.
- Quanto ha speso in tutto ogni cliente che ha fatto almeno un intervento, dal più alto.
- Le auto mai riparate, con nome e cognome del proprietario.
- L'intervento più costoso: targa, descrizione, costo e cognome del cliente.
- Quanti tagliandi sono stati fatti e qual è il loro costo medio.
- Gli interventi del primo semestre 2026, in ordine di data.
Controlla i risultati
Se le tue query restituiscono queste righe, sono giuste (l'ordine delle colonne e i loro nomi possono essere diversi).
Query 1 – 3 righe
| targa | modello | data | descrizione | costo |
|---|---|---|---|---|
| AB123CD | Panda | 2026-01-15 | Tagliando | 180.00 |
| AB123CD | Panda | 2026-06-20 | Cambio pneumatici | 320.00 |
| EF456GH | 500 | 2026-10-01 | Tagliando | 195.00 |
Query 2 – 3 righe
| nome | cognome | spesa |
|---|---|---|
| Laura | Conti | 1060.00 |
| Mario | Esposito | 695.00 |
| Francesca | Villa | 224.00 |
Query 3 – 1 riga
| targa | modello | nome | cognome |
|---|---|---|---|
| MN012OP | Yaris | Giorgio | Marino |
Query 4 – 1 riga
| targa | descrizione | costo | cognome |
|---|---|---|---|
| IJ789KL | Sostituzione frizione | 850.00 | Conti |
Query 5 – 1 riga
| tagliandi | costo_medio |
|---|---|
| 3 | 195.00 |
Query 6 – 5 righe
| data | targa | descrizione | costo |
|---|---|---|---|
| 2026-01-15 | AB123CD | Tagliando | 180.00 |
| 2026-02-10 | IJ789KL | Sostituzione frizione | 850.00 |
| 2026-03-18 | QR345ST | Revisione | 79.00 |
| 2026-04-02 | QR345ST | Sostituzione batteria | 145.00 |
| 2026-06-20 | AB123CD | Cambio pneumatici | 320.00 |
Esercitazione 5 – Il torneo di calcetto
⭐⭐ Medio · due chiavi esterne verso la stessa tabella, alias multipli, valori NULL
La scuola organizza un torneo di calcetto tra le classi. Ogni partita si gioca tra una squadra di casa e una squadra ospite; finché la partita non è giocata, i gol restano vuoti (NULL).
Lo schema logico
squadre (id, nome, classe) partite (id, data, casa_id*, ospite_id*, gol_casa, gol_ospite) casa_id → squadre(id), ospite_id → squadre(id)
I dati da inserire
squadre
| id | nome | classe |
|---|---|---|
| 1 | I Bit | 5AI |
| 2 | Gli Ottetti | 5BI |
| 3 | Packet Lost | 4AI |
| 4 | Root Access | 4BI |
partite
| id | data | casa_id | ospite_id | gol_casa | gol_ospite |
|---|---|---|---|---|---|
| 1 | 2026-10-05 | 1 | 2 | 3 | 1 |
| 2 | 2026-10-05 | 3 | 4 | 2 | 2 |
| 3 | 2026-10-12 | 1 | 3 | 0 | 2 |
| 4 | 2026-10-12 | 2 | 4 | 4 | 1 |
| 5 | 2026-10-19 | 4 | 1 | 1 | 1 |
| 6 | 2026-10-19 | 3 | 2 | vuoto | vuoto |
Cosa fare
-
Crea il database
es_torneoe scrivi leCREATE TABLE, scegliendo i tipi e i vincoli giusti: chiavi primarie,NOT NULL,UNIQUEeCHECKdove servono, chiavi esterne. -
Inserisci i dati con le
INSERT. -
Scrivi le query:
- Il calendario completo: data, nome della squadra di casa, nome della squadra ospite e gol, in ordine di data.
- Le partite ancora da giocare.
- Le partite finite in pareggio.
- Le vittorie della squadra di casa, con il nome della squadra che ha vinto.
- Tutte le partite dei Bit, giocate in casa o fuori.
- Sfida. I gol segnati in tutto da ogni squadra, in casa e fuori (suggerimento:
UNION ALLin una sottoquery).
Da pensare
- Inserisci il risultato della partita del 19 ottobre tra Packet Lost e Gli Ottetti: 3 a 2.
Controlla i risultati
Se le tue query restituiscono queste righe, sono giuste (l'ordine delle colonne e i loro nomi possono essere diversi).
Query 1 – 6 righe
| data | casa | ospite | gol_casa | gol_ospite |
|---|---|---|---|---|
| 2026-10-05 | I Bit | Gli Ottetti | 3 | 1 |
| 2026-10-05 | Packet Lost | Root Access | 2 | 2 |
| 2026-10-12 | I Bit | Packet Lost | 0 | 2 |
| 2026-10-12 | Gli Ottetti | Root Access | 4 | 1 |
| 2026-10-19 | Root Access | I Bit | 1 | 1 |
| 2026-10-19 | Packet Lost | Gli Ottetti | vuoto | vuoto |
Query 2 – 1 riga
| data | casa | ospite |
|---|---|---|
| 2026-10-19 | Packet Lost | Gli Ottetti |
Query 3 – 2 righe
| data | casa | ospite | gol_casa | gol_ospite |
|---|---|---|---|---|
| 2026-10-05 | Packet Lost | Root Access | 2 | 2 |
| 2026-10-19 | Root Access | I Bit | 1 | 1 |
Query 4 – 2 righe
| data | vincitrice | gol_casa | gol_ospite |
|---|---|---|---|
| 2026-10-05 | I Bit | 3 | 1 |
| 2026-10-12 | Gli Ottetti | 4 | 1 |
Query 5 – 3 righe
| data | casa | ospite | gol_casa | gol_ospite |
|---|---|---|---|---|
| 2026-10-05 | I Bit | Gli Ottetti | 3 | 1 |
| 2026-10-12 | I Bit | Packet Lost | 0 | 2 |
| 2026-10-19 | Root Access | I Bit | 1 | 1 |
Query 6 – 4 righe
| nome | gol_fatti |
|---|---|
| Gli Ottetti | 5 |
| I Bit | 4 |
| Packet Lost | 4 |
| Root Access | 4 |
Esercitazione 6 – La pizzeria a domicilio
⭐⭐⭐ Impegnativo · N:M con attributo (quantità), calcoli nelle query, LIMIT, HAVING
Una pizzeria consegna a domicilio. Ogni ordine appartiene a un cliente, ha data e ora e un indicatore che dice se è già stato consegnato. In un ordine ci sono una o più pizze, ciascuna con la sua quantità.
Lo schema logico
pizze (id, nome, prezzo) clienti (id, nome, cognome, indirizzo) ordini (id, cliente_id*, data_ora, consegnato) cliente_id → clienti(id) dettagli_ordine (ordine_id*, pizza_id*, quantita) ordine_id → ordini(id), pizza_id → pizze(id)
I dati da inserire
pizze
| id | nome | prezzo |
|---|---|---|
| 1 | Margherita | 6,00 |
| 2 | Diavola | 7,50 |
| 3 | Quattro formaggi | 8,00 |
| 4 | Capricciosa | 8,50 |
| 5 | Ortolana | 7,00 |
| 6 | Marinara | 5,00 |
clienti
| id | nome | cognome | indirizzo |
|---|---|---|---|
| 1 | Luca | Moretti | Via Roma 10 |
| 2 | Elisa | Gallo | Corso Francia 25 |
| 3 | Tommaso | Leone | Via Nizza 140 |
ordini
| id | cliente_id | data_ora | consegnato |
|---|---|---|---|
| 1 | 1 | 2026-10-10 19:30 | 1 |
| 2 | 2 | 2026-10-10 20:15 | 1 |
| 3 | 1 | 2026-10-11 20:00 | 1 |
| 4 | 3 | 2026-10-12 19:45 | 0 |
dettagli_ordine
| ordine_id | pizza_id | quantita |
|---|---|---|
| 1 | 1 | 2 |
| 1 | 2 | 1 |
| 2 | 3 | 1 |
| 2 | 4 | 2 |
| 3 | 2 | 3 |
| 4 | 1 | 1 |
| 4 | 5 | 2 |
Cosa fare
-
Crea il database
es_pizzeriae scrivi leCREATE TABLE, scegliendo i tipi e i vincoli giusti: chiavi primarie,NOT NULL,UNIQUEeCHECKdove servono, chiavi esterne. -
Inserisci i dati con le
INSERT. -
Scrivi le query:
- Il dettaglio dell'ordine numero 2: nome della pizza, quantità, prezzo unitario e subtotale.
- Il totale di ogni ordine, con data, ora e cognome del cliente.
- La pizza più venduta, contando le quantità (suggerimento:
ORDER BYeLIMIT 1). - Le pizze che nessuno ha mai ordinato.
- Gli ordini non ancora consegnati, con l'indirizzo di consegna.
- I clienti che in tutto hanno speso più di 30 €.
Da pensare
- Il prezzo delle pizze cambia nel tempo: se domani la Margherita costa 6,50 €, che cosa succede ai totali degli ordini già fatti? Come cambieresti lo schema?
Controlla i risultati
Se le tue query restituiscono queste righe, sono giuste (l'ordine delle colonne e i loro nomi possono essere diversi).
Query 1 – 2 righe
| nome | quantita | prezzo | subtotale |
|---|---|---|---|
| Quattro formaggi | 1 | 8.00 | 8.00 |
| Capricciosa | 2 | 8.50 | 17.00 |
Query 2 – 4 righe
| id | data_ora | cognome | totale |
|---|---|---|---|
| 1 | 2026-10-10 19:30:00 | Moretti | 19.50 |
| 2 | 2026-10-10 20:15:00 | Gallo | 25.00 |
| 3 | 2026-10-11 20:00:00 | Moretti | 22.50 |
| 4 | 2026-10-12 19:45:00 | Leone | 20.00 |
Query 3 – 1 riga
| nome | pizze_vendute |
|---|---|
| Diavola | 4 |
Query 4 – 1 riga
| nome |
|---|
| Marinara |
Query 5 – 1 riga
| id | data_ora | cognome | indirizzo |
|---|---|---|---|
| 4 | 2026-10-12 19:45:00 | Leone | Via Nizza 140 |
Query 6 – 1 riga
| nome | cognome | speso |
|---|---|---|
| Luca | Moretti | 42.00 |
Esercitazione 7 – Le prenotazioni dei laboratori
⭐⭐⭐ Impegnativo · date e orari, TIMESTAMPDIFF, NOT IN con condizioni, self join
I docenti prenotano i laboratori della scuola per le loro classi: per ogni prenotazione si registrano il laboratorio, il docente, la classe, la data e l'ora di inizio e di fine. Due prenotazioni dello stesso laboratorio non dovrebbero sovrapporsi… ma nei dati ce n'è una sbagliata.
Lo schema logico
laboratori (id, nome, posti) docenti (id, nome, cognome) prenotazioni (id, laboratorio_id*, docente_id*, classe, data, ora_inizio, ora_fine) laboratorio_id → laboratori(id), docente_id → docenti(id)
I dati da inserire
laboratori
| id | nome | posti |
|---|---|---|
| 1 | Informatica 1 | 24 |
| 2 | Informatica 2 | 28 |
| 3 | Chimica | 20 |
docenti
| id | nome | cognome |
|---|---|---|
| 1 | Paolo | Rinaldi |
| 2 | Silvia | Gatti |
| 3 | Marco | Testa |
prenotazioni
| id | laboratorio_id | docente_id | classe | data | ora_inizio | ora_fine |
|---|---|---|---|---|---|---|
| 1 | 1 | 1 | 3AI | 2026-10-20 | 08:00 | 10:00 |
| 2 | 2 | 1 | 4BI | 2026-10-20 | 10:00 | 12:00 |
| 3 | 1 | 2 | 5AI | 2026-10-20 | 11:00 | 13:00 |
| 4 | 3 | 3 | 3BC | 2026-10-20 | 08:00 | 09:00 |
| 5 | 2 | 2 | 1A | 2026-10-21 | 09:00 | 11:00 |
| 6 | 1 | 1 | 3AI | 2026-10-22 | 08:00 | 10:00 |
| 7 | 1 | 3 | 4AI | 2026-10-20 | 09:00 | 11:00 |
Cosa fare
-
Crea il database
es_laboratorie scrivi leCREATE TABLE, scegliendo i tipi e i vincoli giusti: chiavi primarie,NOT NULL,UNIQUEeCHECKdove servono, chiavi esterne. -
Inserisci i dati con le
INSERT. -
Scrivi le query:
- Le prenotazioni del 20 ottobre 2026: laboratorio, ora di inizio e di fine, classe e cognome del docente, in ordine di laboratorio e di ora.
- Quante ore di laboratorio ha prenotato in tutto ogni docente (suggerimento:
TIMESTAMPDIFF(HOUR, inizio, fine)). - I laboratori liberi il 20 ottobre 2026 alle 12:00 (un laboratorio è occupato se una prenotazione inizia entro le 12:00 e finisce dopo).
- I docenti con almeno 3 prenotazioni.
- Sfida. Trova le prenotazioni sovrapposte: stesso laboratorio, stessa data, orari che si accavallano (suggerimento: la tabella
prenotazioniunita con sé stessa, con due alias).
Controlla i risultati
Se le tue query restituiscono queste righe, sono giuste (l'ordine delle colonne e i loro nomi possono essere diversi).
Query 1 – 5 righe
| nome | ora_inizio | ora_fine | classe | cognome |
|---|---|---|---|---|
| Chimica | 08:00:00 | 09:00:00 | 3BC | Testa |
| Informatica 1 | 08:00:00 | 10:00:00 | 3AI | Rinaldi |
| Informatica 1 | 09:00:00 | 11:00:00 | 4AI | Testa |
| Informatica 1 | 11:00:00 | 13:00:00 | 5AI | Gatti |
| Informatica 2 | 10:00:00 | 12:00:00 | 4BI | Rinaldi |
Query 2 – 3 righe
| cognome | ore |
|---|---|
| Rinaldi | 6 |
| Gatti | 4 |
| Testa | 3 |
Query 3 – 2 righe
| nome |
|---|
| Chimica |
| Informatica 2 |
Query 4 – 1 riga
| nome | cognome | prenotazioni |
|---|---|---|
| Paolo | Rinaldi | 3 |
Query 5 – 1 riga
| prima | seconda | nome | data | ora_inizio | ora_fine | ora_inizio | ora_fine |
|---|---|---|---|---|---|---|---|
| 1 | 7 | Informatica 1 | 2026-10-20 | 08:00:00 | 10:00:00 | 09:00:00 | 11:00:00 |
⭐⭐⭐ Impegnativo · dal testo al database, come all'Esame di Stato
Questa volta niente schema già pronto: si parte dal testo, come nella seconda prova. Prima di cominciare, rileggi il metodo della lezione 16.
Un cinema multisala vuole gestire la programmazione e la vendita dei biglietti. Il cinema ha alcune sale, ciascuna con un nome e un numero di posti. Di ogni film si registrano titolo, durata, genere e anno di uscita. La programmazione è fatta di proiezioni: ogni proiezione è un film, in una sala, in un giorno e a un'ora precisi, con un prezzo del biglietto (che può cambiare, per esempio, tra pomeriggio e sera). Alla cassa o online si vendono i biglietti: ogni acquisto riguarda una proiezione e uno o più posti, e va registrato con data e ora. Non si possono vendere più biglietti dei posti della sala.
Cosa fare
-
Scrivi le ipotesi aggiuntive che ti servono (per esempio: i posti sono numerati?).
-
Disegna il modello E/R, con entità, attributi, associazioni e cardinalità.
-
Ricava lo schema logico e scrivi il DDL con tutti i vincoli.
-
Inserisci dati di prova: almeno 3 sale, 4 film, 6 proiezioni in due giorni e alcuni biglietti, con almeno uno spettacolo tutto esaurito.
-
Scrivi le query:
- la programmazione di un certo giorno: ora, film, sala e prezzo, in ordine di ora;
- i posti ancora liberi per ogni proiezione, comprese quelle senza biglietti venduti;
- l'incasso totale di ogni film, dal più alto;
- il film con più spettatori in un certo mese;
- le sale non usate in un certo giorno;
- le proiezioni con il tutto esaurito.
Seconda parte (scegli un quesito)
- Il cinema vuole i posti numerati (fila e numero). Come cambia lo schema? Come eviti di vendere due volte lo stesso posto per la stessa proiezione?
- Due casse vendono nello stesso istante l'ultimo posto libero. Che cosa può succedere? Come lo eviti con una transazione?
Qui i risultati attesi non ci sono, perché dipendono dalle tue ipotesi e dai tuoi dati: confronta il tuo lavoro con il docente.
Quando hai finito, i database che hai creato qui ti servono ancora: nelle esercitazioni PHP diventano applicazioni web.