Composers, pieces and concerts¶
Problem¶
A database of composers, the pieces they wrote and the concerts in which pieces
are played (Programmazione says which piece is played in which concert, and in which
position). Write four queries on it.
Schema and test data¶
CREATE TABLE Compositori ( codice integer NOT NULL PRIMARY KEY,
cognome text ,
nome text );
CREATE TABLE Pezzi ( codice integer NOT NULL PRIMARY KEY,
titolo text,
autore integer NOT NULL REFERENCES Compositori,
durata integer);
CREATE TABLE Concerti ( codice integer NOT NULL PRIMARY KEY,
titolo text ,
descrizione text );
CREATE TABLE Programmazione ( pezzo integer NOT NULL REFERENCES Pezzi,
concerto integer NOT NULL REFERENCES Concerti,
posizione integer,
PRIMARY KEY(pezzo, concerto) );
-- Test data (not part of the exercise): two composers named Rossi, a composer
-- with no pieces, a piece never played, and a tie for the most pieces played.
INSERT INTO Compositori VALUES (1, 'Rossi', 'Gioachino'), (2, 'Rossi', 'Luigi'),
(3, 'Bianchi', 'Anna'), (4, 'Verdi', 'Giuseppe');
INSERT INTO Pezzi VALUES (10, 'Overture A', 1, 8), (11, 'Aria B', 1, 4),
(12, 'Sonata C', 2, 12), (13, 'Studio D', 3, 6),
(14, 'Notturno E', 3, 7), (15, 'Preludio F', 2, 3);
INSERT INTO Concerti VALUES (100, 'Spring', 'Season opening'), (101, 'Summer', 'Open air');
INSERT INTO Programmazione VALUES (10, 100, 1), (11, 100, 2), (13, 100, 3),
(10, 101, 1), (14, 101, 2), (12, 101, 3);
The schema is the one given in the exercise; the test data are mine.
Queries¶
Query 1 · Long pieces by composers named Rossi¶
Find the pieces longer than 5 whose author is a composer with surname 'Rossi'. Show the
composer's code and the code, title and length of the piece; order by composer and piece.
SELECT C1.codice AS codiceCompositore, C2.codice AS codicePezzo, C2.titolo, C2.durata
FROM Compositori AS C1
JOIN Pezzi AS C2
ON C1.codice = C2.autore
WHERE C2.durata > 5 AND C1.cognome = 'Rossi'
ORDER BY C1.codice, C2.codice
| codiceCompositore | codicePezzo | titolo | durata |
|---|---|---|---|
| 1 | 10 | Overture A | 8 |
| 2 | 12 | Sonata C | 12 |
Query 2 · Pieces never played¶
Find code and title of the pieces that are not in any concert, ordered by code.
SELECT C1.codice, C1.titolo
FROM Pezzi AS C1
LEFT JOIN Programmazione AS C2
ON C1.codice = C2.pezzo
WHERE C2.pezzo IS NULL
ORDER BY C1.codice
| codice | titolo |
|---|---|
| 15 | Preludio F |
The anti-join pattern: an outer join, then keep the rows where the optional side is missing.
Query 3 · Distinct pieces played, per composer¶
For each composer, the number of different pieces played in at least one concert. Ignore composers with no piece played; show code, surname, name and number of pieces.
SELECT C1.codice, C1.cognome, C1.nome, COUNT(DISTINCT C3.pezzo) AS numeroPezzi
FROM Compositori AS C1
JOIN Pezzi AS C2
ON C1.codice = C2.autore
JOIN Programmazione AS C3
ON C2.codice = C3.pezzo
GROUP BY C1.codice, C1.cognome, C1.nome
| codice | cognome | nome | numeroPezzi |
|---|---|---|---|
| 1 | Rossi | Gioachino | 2 |
| 2 | Rossi | Luigi | 1 |
| 3 | Bianchi | Anna | 2 |
COUNT(DISTINCT C3.pezzo) counts a piece once even when it is played in several concerts
(Overture A is in both). The inner joins drop the composers with nothing played, as required.
Query 4 · Composers with the most pieces played¶
Find the composer (or composers) with the largest number of different pieces played, as computed in Query 3. Show code, name, surname and number of pieces; order by code.
CREATE VIEW massimo_numero_pezzi AS
SELECT C1.codice, C1.cognome, C1.nome, COUNT(DISTINCT C3.pezzo) AS numeroPezzi
FROM Compositori AS C1
JOIN Pezzi AS C2
ON C1.codice = C2.autore
JOIN Programmazione AS C3
ON C2.codice = C3.pezzo
GROUP BY C1.codice, C1.cognome, C1.nome
ORDER BY C1.codice;
SELECT codice, cognome, nome, numeroPezzi
FROM massimo_numero_pezzi
WHERE numeroPezzi = (SELECT MAX(numeroPezzi) FROM massimo_numero_pezzi)
| codice | cognome | nome | numeroPezzi |
|---|---|---|---|
| 1 | Rossi | Gioachino | 2 |
| 3 | Bianchi | Anna | 2 |
Takeaways¶
- "Not in any…" is an outer join filtered on
IS NULL(or aNOT IN/NOT EXISTS). COUNT(DISTINCT …)when the joins can repeat the thing being counted.- Reusing a query as a view keeps the "maximum" query short and readable.