Esercizi di Basi di dati - SQL August 28, 2008 1 SQL - Soluzioni Sono di seguito riportate un insieme di interrogazioni risolte in SQL. Ogni interrogazione è caratterizzata dalle tabelle sulle quali deve essere eseguita, dal testo in linguaggio naturale dell interrogazione e da una o più possibili soluzioni in SQL. In ogni tabella gli attributi sottolineati identificano la chiave primaria della tabella. 1.1 Interrogazioni base: proiezione, selezione e join Interrogazione 1. Selezionare il nome di tutte le riviste presenti nella base di dati. SELECT NomeR FROM RIVISTA; Interrogazione 2. Selezionare il codice e il nome di tutte le riviste presenti nella base di dati. SELECT CodR, NomeR FROM RIVISTA; 1
Interrogazione 3. Selezionare il nome di tutte le riviste pubblicate dall editore Editore1. SELECT NomeR FROM RIVISTA WHERE Editore= Editore1 ; Interrogazione 4. Selezionare il codice delle riviste che hanno pubblicato almeno 1 articolo. SELECT DISTINCT CodR FROM ARTICOLO; Interrogazione 5. Selezionare il codice e il nome delle riviste che hanno pubblicato almeno 1 articolo. SELECT DISTINCT CodR, NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR; Interrogazione 6. Selezionare il codice delle riviste che hanno pubblicato almeno 1 articolo di motociclismo (Argomento= motociclismo ). SELECT DISTINCT CodR FROM ARTICOLO WHERE Argomento= Motociclismo ; 2
Interrogazione 7. Selezionare il codice e il nome delle riviste che hanno pubblicato almeno 1 articolo di motociclismo. SELECT DISTINCT RIVISTA.CodR, NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR AND Argomento= Motociclismo ; Interrogazione 8. Selezionare il codice e il nome delle riviste che hanno pubblicato almeno 1 articolo di motociclismo oppure di automobilismo. SELECT DISTINCT RIVISTA.CodR, NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR AND (Argomento= Motociclismo OR Argomento= Automobilismo ); Interrogazione 9. GARA(CodG, Luogo, Data, Disciplina) ATLETA(CodA, Nome, Nazione, DataNascita) PARTECIPAZIONE(CodG, CodA,PosizioneArrivo, Tempo) Selezionare il codice e il nome degli atleti italiani che sono giunti primi in almeno una gara di lancio del peso. SELECT DISTINCT A.CodA, Nome FROM ATLETA A, PARTECIPAZIONE P, GARA G WHERE P.CodA=A.CodA AND P.CodG=G.CodG AND Disciplina= lancio del peso AND Nazione= Italia AND PosizioneArrivo=1; 3
Interrogazione 10. STABILIMENTO(CodS, Nome, Indirizzo, Stato) LINEA MONTAGGIO(CodS, NumL, DataInstallazioneLinea) TIPO AUTOVETTURA(CodTA, Nome, NumeroPosti) PRODUZIONE(CodS, NumL, CodTA, NumeroAutovetture) Selezionare i codici delle linee di montaggio presso le quali sono state prodotte almeno 10000 autovetture punto. SELECT DISTINCT LM.CodS, LM.NumL FROM LINEA_MONTAGGIO LM, PRODUZIONE P, TIPO_AUTOVETTURA TA WHERE P.CodS=LM.CodS AND P.NumL=LM.NumL AND P.CodTA=TA.CodTA AND P.NumeroAutovetture>=10000 AND TA.Nome= punto ; 4
1.2 Interrogazioni annidate: IN, NOT IN, EXISTS, NOT EXISTS Interrogazione 1. Selezionare il codice e il nome delle riviste che hanno pubblicato almeno 1 articolo di motociclismo. SELECT CodR, NomeR FROM RIVISTA WHERE CodR IN (SELECT CodR FROM ARTICOLO WHERE Argomento= Motociclismo ); Oppure SELECT CodR, NomeR FROM RIVISTA R WHERE EXISTS (SELECT * FROM ARTICOLO A WHERE A.CodR=R.CodR AND Argomento= Motociclismo ); Interrogazione 2. Selezionare il nome delle riviste che hanno pubblicato almeno un articolo di motociclismo e almeno un articolo di automobilismo. SELECT NomeR FROM RIVISTA WHERE CodR IN (SELECT CodR FROM ARTICOLO WHERE Argomento= motociclismo ) AND CodR IN (SELECT CodR FROM ARTICOLO WHERE Argomento= automobilismo ); Oppure SELECT DISTINCT NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR AND Argomento= motociclismo AND RIVISTA.CodR IN (SELECT CodR FROM ARTICOLO WHERE Argomento= automobilismo ); 5
Oppure SELECT NomeR FROM RIVISTA R WHERE EXISTS (SELECT * FROM ARTICOLO A1 WHERE A1.CodR=R.CodR AND Argomento= motociclismo ) AND EXISTS (SELECT * FROM ARTICOLO A2 WHERE A2.CodR=R.CodR AND Argomento= motociclismo ); Interrogazione 3. STABILIMENTO(CodS, Nome, Indirizzo, Stato) LINEA MONTAGGIO(CodS, NumL, DataInstallazioneLinea) TIPO AUTOVETTURA(CodTA, Nome, NumeroPosti) PRODUZIONE(CodS, NumL, CodTA, NumeroAutovetture) Selezionare i codici delle linee di montaggio presso le quali sono state prodotte almeno 10000 autovetture punto e almeno 20000 cinquecento. SELECT CodS, NumL FROM LINEA_MONTAGGIO LM WHERE EXISTS (SELECT * FROM PRODUZIONE P, TIPO_AUTOVETTURA TA WHERE P.CodTA=TA.CodTA AND P.NumeroAutovetture>=10000 AND TA.Nome= punto AND P.CodS=LM.CodS AND P.NumL=LM.NumL) AND EXISTS (SELECT * FROM PRODUZIONE P, TIPO_AUTOVETTURA TA WHERE P.CodTA=TA.CodTA AND P.NumeroAutovetture>=20000 AND TA.Nome= cinquecento AND P.CodS=LM.CodS AND P.NumL=LM.NumL); Oppure 6
SELECT CodS, NumL FROM LINEA_MONTAGGIO WHERE (CodS, NumL) IN (SELECT CodS, NumL FROM PRODUZIONE P, TIPO_AUTOVETTURA TA WHERE P.CodTA=TA.CodTA AND P.NumeroAutovetture>=10000 AND TA.Nome= punto ) AND (CodS, NumL) IN (SELECT CodS, NumL FROM PRODUZIONE P, TIPO_AUTOVETTURA TA WHERE P.CodTA=TA.CodTA AND P.NumeroAutovetture>=20000 AND TA.Nome= cinquecento ); Interrogazione 4. Selezionare il nome delle riviste che non hanno mai pubblicato articoli di motociclismo. SELECT NomeR FROM RIVISTA WHERE CodR NOT IN (SELECT CodR FROM ARTICOLO WHERE Argomento= motociclismo ); Oppure SELECT NomeR FROM RIVISTA R WHERE NOT EXISTS (SELECT * FROM ARTICOLO A WHERE Argomento= motociclismo AND A.CodR=R.CodR); Interrogazione 5. Selezionare gli editori che non hanno mai pubblicato articoli di motociclismo. SELECT Editore FROM RIVISTA WHERE Editore NOT IN (SELECT Editore FROM ARTICOLO A, RIVISTA R WHERE A.CodR=R.CodR AND Argomento= motociclismo ); 7
Interrogazione 6. Selezionare il nome delle riviste che hanno pubblicato solo articoli di motociclismo. SELECT DISTINCT NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR AND RIVISTA.CodR NOT IN (SELECT CodR FROM ARTICOLO WHERE Argomento<> motociclismo ); Interrogazione 7. ORCHESTRA(CodO, NomeO, NomrDirettore, numelementi) CONCERTI(CodC, Data, CodO, CodS, PrezzoBiglietto) SALE(CodS, NomeS, Città, Capienza) Selezionare il codice e il nome delle orchestre con più di 30 elementi che hanno tenuto concerti sia a Torino, sia a Milano e non hanno mai tenuto concerti a Bologna. SELECT CodO, NomeO FROM ORCHESTRA WHERE NumElementi>30 AND CodO IN (SELECT C1.CodO FROM CONCERTI C1, SALE S1 WHERE C1.CodS=S1.CodS AND S1.Citta= Torino ) AND CodO IN (SELECT C2.CodO FROM CONCERTI C2, SALE S2 WHERE C2.CodS=S2.CodS AND S2.Citta= Milano ) AND CodO NOT IN (SELECT C3.CodO FROM CONCERTI C3, SALE S3 WHERE C3.CodS=S3.CodS AND S3.Citta= Bologna ); 8
1.3 Funzioni aggregate e Group by: COUNT(), AVG(), SUM(), MAX() MIN() e GROUP BY Interrogazione 1. Selezionare il numero di articoli di motociclismo presenti nella base di dati. SELECT COUNT(*) FROM ARTICOLO WHERE Argomento= Motociclismo ; Interrogazione 2. Selezionare il numero di articoli pubblicati sulla rivista D100 (CodR= D100 ). SELECT COUNT(*) FROM ARTICOLO WHERE CodR= D100 ; Interrogazione 3. Selezionare il codice e il numero di articoli pubblicati su ogni rivista. SELECT CodR, COUNT(*) FROM ARTICOLO GROUP BY CodR; Interrogazione 4. Selezionare il codice, il nome e il numero di articoli pubblicati su ogni rivista. SELECT RIVISTA.NomeR, COUNT(*) FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR; GROUP BY RIVISTA.CodR, NomeR; 9
Interrogazione 5. Selezionare il nome e il numero di articoli pubblicati su ogni rivista. SELECT NomeR, COUNT(*) FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR; GROUP BY RIVISTA.CodR, NomeR; Interrogazione 6. Selezionare il codice delle riviste che hanno pubblicato almeno due articoli di motociclismo. SELECT CodR FROM ARTICOLO WHERE Argomento= motociclismo GROUP BY CodR HAVING COUNT(*)>1 Interrogazione 7. Selezionare il nome delle riviste che hanno pubblicato almeno due articoli di motociclismo. SELECT NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR AND Argomento= motociclismo GROUP BY RIVISTA.CodR, NomeR HAVING COUNT(*)>1 10
Interrogazione 8. Selezionare il codice e il nome delle riviste che hanno pubblicato un articolo, ed uno solo, di motociclismo (possono aver scritto quanti articoli desiderano relativamente ad altri argomenti). SELECT RIVISTA.CodR, NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR AND Argomento= motociclismo GROUP BY RIVISTA.CodR, NomeR HAVING COUNT(*)=1 Interrogazione 9. CORSO (CodCorso, NomeC, Anno, Semestre) ORARIO LEZIONI (CodCorso, GiornoSettimana, OraInizio, OraFine, Aula) Selezionare codice corso, nome corso e numero totale di ore di lezione settimanali per i corsi del terzo anno per cui il numero complessivo di ore di lezione settimanali è superiore a 10 e le lezioni sono in più di tre giorni diversi della settimana. SELECT C.CodCorso, C.NomeC, SUM(OraFine-OraInizio) FROM CORSO C, ORARIO_LEZIONI OL WHERE C.CodCorso=OL.CodCorso AND C.Anno = 3 GROUP BY C.Corso, C.NomeC HAVING SUM(OraFine-OraInizio)>10 AND COUNT(DISTINCT GiornoSettimana)>3; 11
Interrogazione 10. GARA(CodG, Luogo, Data, Disciplina) ATLETA(CodA, Nome, Nazione, DataNascita) PARTECIPAZIONE(CodG, CodA,PosizioneArrivo, Tempo) Selezionare le nazioni per cui concorrono almeno 5 atleti nati prima del 1980, ciascuno dei quali abbia partecipato ad almeno 10 gare di sci di fondo. SELECT Nazione FROM ATLETA WHERE DataNascita< 1/1/1980 AND CodA IN (SELECT CodA FROM PARTECIPAZIONE P,GARA G WHERE P.CodG=G.CodG AND Disciplina= fondo GROUP BY CodA HAVING COUNT(*)>=10) GROUP BY Nazione HAVING COUNT(*)>=5; Interrogazione 11. APPARTAMENTO(CodA, Superficie, Indirizzo, Città) CONTRATTO AFFITTO(CodA, DataInizio, DataFine, NomePersona, RettaMensile) Selezionare il nome delle persone che hanno stipulato più di due contratti di affitto per lo stesso appartamento. SELECT NomePersona FROM CONTRATTO_AFFITTO GROUP BY NomePersona,CodA HAVING COUNT(*)>2; Interrogazione 12. APPARTAMENTO(CodA, Superficie, Indirizzo, Città) CONTRATTO AFFITTO(CodA, DataInizio, DataFine, NomePersona, RettaMensile) Selezionare il nome delle persone che hanno stipulato più di due contratti di affitto nel corso della stessa data. SELECT NomePersona FROM CONTRATTO_AFFITTO GROUP BY NomePersona,DataInizio HAVING COUNT(*)>2; 12
Interrogazione 13. Selezionare il nome delle riviste che hanno pubblicato un numero di articoli di motociclimo compreso tra 10 e 25. SELECT NomeR FROM RIVISTA, ARTICOLO WHERE RIVISTA.CodR=ARTICOLO.CodR AND Argomento= motociclismo GROUP BY RIVISTA.CodR, NomeR HAVING COUNT(*)>=10 AND COUNT(*)<=25; Interrogazione 14. Selezionare il nome delle riviste che hanno pubblicato almeno 10 articoli di automobilismo e almeno 25 articoli di motociclimo. SELECT NomeR FROM RIVISTA WHERE CodR IN (SELECT CodR ARTICOLO WHERE Argomento= automibilismo GROUP BY CodR HAVING COUNT(*)>=10) AND CodR IN (SELECT CodR ARTICOLO WHERE Argomento= motociclismo GROUP BY CodR HAVING COUNT(*)>=25); Interrogazione 15. Selezionare il nome delle riviste che hanno pubblicato meno di 25 articoli di motociclimo. SELECT NomeR FROM RIVISTA WHERE CodR NOT IN (SELECT CodR ARTICOLO WHERE Argomento= motociclismo GROUP BY CodR HAVING COUNT(*)>=25); 13
Interrogazione 16. Selezionare il nome delle riviste che hanno pubblicato almeno 10 articoli di automobilismo e meno di 25 articoli di motociclimo. SELECT NomeR FROM RIVISTA WHERE CodR IN (SELECT CodR ARTICOLO WHERE Argomento= automibilismo GROUP BY CodR HAVING COUNT(*)>=10) AND CodR NOT IN (SELECT CodR ARTICOLO WHERE Argomento= motociclismo GROUP BY CodR HAVING COUNT(*)>=25); Interrogazione 17. QUIZ(CodQuiz, Argomento, Punteggio) STUDENTE(Matricola, Nome, Indirizzo, Città) RISULTATO TEST(Matricola, CodQuiz,RispostaCorretta) Selezionare il nome degli studenti di Torino che hanno conseguito il punteggio massimo possibile nei quiz di matematica. SELECT Nome FROM STUDENTE S, RISULTATO_TEST R, QUIZ Q WHERE Citta= Torino AND R.Matricola=S.Matricola AND R.CodQuiz=Q.CodQuiz AND RispostaCorretta= si AND Argomento= matematica GROUP BY S.Matricola, Nome HAVING SUM(Punteggio)=(SELECT SUM(Punteggio) FROM QUIZ WHERE Argomento= matematica ); 14
Interrogazione 18. RIUNIONE(CodR, Descrizione, DataRiunione) DIPENDENTE(CodD, Nome, Cognome, DataNascita, Città) PARTECIPA RIUNIONE(CodD, CodR) Visualizzare il codice dei dipendenti che hanno partecipato a tutte le riunioni che si sono svolte. SELECT CodD FROM PARTECIPA_RIUNIONE PR WHERE PR.CodR=R.CodR GROUP BY CodD HAVING COUNT(*)=(SELECT COUNT(*) FROM RIUNIONE); Interrogazione 19. RIUNIONE(CodR, Descrizione, DataRiunione) DIPENDENTE(CodD, Nome, Cognome, DataNascita, Città) PARTECIPA RIUNIONE(CodDip, CodR) Visualizzare il codice dei dipendenti che hanno partecipato almeno a tutte le riunioni alle quali ha partecipato il dipendente D100 (CodD= D100 ). SELECT CodD FROM PARTECIPA_RIUNIONE AND CodR IN (SELECT CodR FROM PARTECIPA_RIUNIONE WHERE CodD= D100 ) GROUP BY CodD HAVING COUNT(*)=(SELECT COUNT(*) FROM PARTECIPA_RIUNIONE WHERE CodD= D100 ) 15
Interrogazione 20. RIUNIONE(CodR, Descrizione, DataRiunione) DIPENDENTE(CodD, Nome, Cognome, DataNascita, Città) PARTECIPA RIUNIONE(CodDip, CodR) Visualizzare il codice dei dipendenti che hanno partecipato solamente alle riunioni alle quali ha partecipato il dipendente D100 (CodD= D100 ). SELECT CodD FROM DIPENDENTE D WHERE CodD NOT IN (SELECT CodD FROM PARTECIPA_RIUNIONE WHERE CodR NOT IN (SELECT CodR FROM PARTECIPA_RIUNIONE WHERE CodD= D100 )); Oppure SELECT CodD FROM DIPENDENTE D WHERE NOT EXISTS (SELECT * FROM PARTECIPA_RIUNIONE PR WHERE PR.CodD=D.CodD AND PR.CodR NOT IN (SELECT CodR FROM PARTECIPA_RIUNIONE WHERE CodD= D100 )); 16
Interrogazione 21. RIUNIONE(CodR, Descrizione, DataRiunione) DIPENDENTE(CodD, Nome, Cognome, DataNascita, Città) PARTECIPA RIUNIONE(CodDip, CodR) Visualizzare il codice dei dipendenti che hanno partecipato a tutte e sole le riunioni alle quali ha partecipato il dipendente D100 (CodD= D100 ). SELECT CodD FROM PARTECIPA_RIUNIONE AND CodR IN (SELECT CodR FROM PARTECIPA_RIUNIONE WHERE CodD= D100 ) AND CodD NOT IN (SELECT CodD FROM PARTECIPA_RIUNIONE WHERE CodR NOT IN (SELECT CodR FROM PARTECIPA_RIUNIONE WHERE CodD= D100 )) GROUP BY CodD HAVING COUNT(*)=(SELECT COUNT(*) FROM PARTECIPA_RIUNIONE WHERE CodD= D100 ) 17
1.4 Uso della correlazione Interrogazione 1. ALLOGGIO(CodA, Indirizzo,Città,Superficie,CostoAffittoMensile) CONTRATTO-AFFITTO(CodC, DataInizio,DataFine,NomePersona,CodA) Selezionare il codice, l indirizzo e la città degli alloggi che hanno una superficie superiore alla superficie media degli alloggi delle città in cui si trovano. SELECT CodA, Indirizzo, Citta FROM ALLOGGIO A1 WHERE Superficie>(SELECT AVG(Superficie) FROM ALLOGGIO A2 WHERE A2.Citta=A1.Citta); Interrogazione 2. SALA RIUNIONI(CodS, NomeSala, NumeroMaxPosti, Proiettore) PRENOTAZIONE SALA(CodS, Data, OraInizio, OraFine, CodDip) DIPENDENTE(CodDip, Nome, Cognome, DataNascita, Città) Visualizzare per ogni sala che è stata prenotata almeno una volta il codice della sala, il nome della sala e il numero di prenotazioni relativamente all ultima data in cui la sala è stata prenotata. SELECT S.CodS, NomeSala, COUNT(*) FROM SALA_RIUNIONI S, PRENOTAZIONE_SALA P WHERE S.CodS=P.CodS AND P.Data=(SELECT MAX(Data) FROM PRENOTAZIONE_SALA P2 WHERE P2.CodS=S.CodS) GROUP BY S.CodS, NomeSala; Oppure SELECT S.CodS, NomeSala, COUNT(*) FROM SALA_RIUNIONI S, PRENOTAZIONE_SALA P WHERE S.CodS=P.CodS AND NOT EXISTS (SELECT * FROM PRENOTAZIONE_SALA P2 WHERE P2.CodS=S.CodS AND P2.Data>P.Data) GROUP BY S.CodS, NomeSala; 18
Interrogazione 3. PERSONE(CodFisc, Nome, Cognome, Indirizzo, Città) MULTE(IdMulta, CodFisc, DataMulta, Somma) Selezionare il nome e il cognome delle persone per cui il numero di multe ricevute nel 2005 è superiore al numero di multe ricevute nel 2004 dalla persona stessa. SELECT Nome, Cognome FROM PERSONE P, MULTE M WHERE P.CodFisc=M.CodFisc AND DataMulta>= 1/1/2005 AND DataMulta<= 31/12/2005 GROUP BY P.CodFisc, Nome, Cognome HAVING COUNT(*)>(SELECT COUNT(*) FROM MULTE M2 WHERE M2.CodFisc=P.CodFisc AND DataMulta>= 1/1/2004 AND DataMulta<= 31/12/2004 ); 19