Esercizio - Algebra relazionale estesa su pizzeria, ristoranti e conteggi con NULL (esercizi di algebra estesa del corso)
In questa pagina 4
Testo (slide di algebra relazionale estesa del corso di Basi di Dati, Ing. Informatica UniPD). Quattro gruppi di domande:
- Pizzeria,
Pizzeria(Pizza, Prezzo, Quantita): l'incasso di ogni tipo di pizza; l'incasso totale e l'incasso massimo; - Pizzeria con più sedi,
Pizzeria(ID, Sede, Pizza, Prezzo, Quantita): l'incasso di ogni sede; - Ristoranti,
Restaurant(Name, Date, PriceMenu, Seats): per ogni ristorante l'incasso totale e medio (tre ristoranti, due giorni); - NULL: come si comportano , , con valori nulli e con il raggruppamento.
1. Incasso per tipo di pizza, totale e massimo
L'incasso di una pizza è : un valore calcolato tra attributi della stessa tupla, quindi una proiezione generalizzata.
| Pizza | Totale |
|---|---|
| Margherita | 80 |
| Capricciosa | 200 |
| Funghi | 18 |
| Marinara | 78 |
SQL: SELECT Pizza, Prezzo * Quantita AS Totale FROM Pizzeria;.
Incasso totale e massimo. Su INCOME si applica un'aggregazione con due funzioni: una sola tupla con due attributi.
perché e il massimo è quello della Capricciosa. Per dare nomi leggibili: . In SQL basta una query: SELECT SUM(Prezzo*Quantita) AS TotIncome, MAX(Prezzo*Quantita) AS MaxIncome FROM Pizzeria; (le due funzioni lavorano su un'espressione, quindi la proiezione intermedia non serve).
Errore nel materiale del corso. Nella slide introduttiva la Capricciosa ha prezzo 11 (e totale 220), mentre le slide con la soluzione usano 10 (totale 200, somma 376). I risultati 376 e 200 valgono con il prezzo 10; con 11 sarebbero 396 e 220 (verificato). È una discrepanza tra una slide e le successive.
2. Incasso di ogni sede
Sedi: , , , .
Il dato che serve non è un attributo, e va sommato su un gruppo: raggruppamento per Sede con la somma dell'incasso di ogni riga.
Passi: la proiezione generalizzata calcola 80, 220, 18, 78; i gruppi sono Vicenza () e Padova (). Grado , cardinalità 2 (due gruppi).
| Sede | SUM(Incasso) |
|---|---|
| Vicenza | 158 |
| Padova | 238 |
SQL: SELECT Sede, SUM(Prezzo * Quantita) AS Incasso FROM Pizzeria GROUP BY Sede;.
3. Ristoranti: totale e media per ristorante
Restaurant: , , , , (con Name abbreviato).
Passo 1: l'incasso di ogni riga (menù per posti):
| Name | Date | Income |
|---|---|---|
| 10/12 | 8000 | |
| 10/12 | 18000 | |
| 11/12 | 21000 | |
| 11/12 | 15000 | |
| 11/12 | 4200 |
Passo 2: raggruppamento per ristorante con somma e media:
| Name | SUM(Income) | AVG(Income) |
|---|---|---|
| 23000 | 11500 | |
| 39000 | 19500 | |
| 4200 | 4200 |
ha un solo giorno: somma e media coincidono. Si può rinominare con . In SQL: SELECT Name, SUM(PriceMenu*Seats) AS Total, AVG(PriceMenu*Seats) AS Average FROM Restaurant GROUP BY Name;.
Errore nel materiale del corso. Le slide riportano per le prime quattro righe incassi di 800, 1800, 2100 e 1500, e quindi totali 2300, 3900 (e medie 1150, 1950). Con i dati della tabella , , , : i valori corretti sono 8000, 18000, 21000, 15000, con totali 23000 e 39000 e medie 11500 e 19500. Solo la riga di () è giusta nella slide (verificato su SQLite). La procedura delle slide è comunque quella giusta.
Estensione: il ristorante con l'incasso totale massimo (pattern del massimo della nota di teoria). Con (totale per ristorante) e (il massimo dei totali):
In SQL: ... GROUP BY Name HAVING SUM(PriceMenu*Seats) = (SELECT MAX(t) FROM (SELECT SUM(PriceMenu*Seats) AS t FROM Restaurant GROUP BY Name) AS q): restituisce solo (provato; in PostgreSQL l'alias q è obbligatorio).
4. NULL e aggregazione
Esami. Exam(Student, Date, Mark, Course): , , , , .
| Espressione | Risultato | Spiegazione |
|---|---|---|
| 5 | conta le tuple, anche con voto nullo | |
| 3 | solo i voti non nulli | |
| 63 | ||
| 21 | , non | |
| , | 25, 18 | solo valori non nulli |
| , , | l'ultimo studente ha solo NULL: la media è NULL |
Con COALESCE(Mark, 0) la media diventerebbe : contare il "nessun voto" come zero è una scelta di significato, non un dettaglio.
Lavoratori. Worker(Badge, Name, Surname, Car): , , , , , .
| Espressione | Risultato |
|---|---|
| 6 | |
| (SQL standard) | 3 (Volvo, Fiat, Fiat) |
| 2 (Volvo, Fiat) | |
| 6 gruppi (ogni badge è unico) | |
| 4 gruppi: , , , | |
| 3 gruppi: , , |
Il raggruppamento tratta i NULL come un gruppo unico: i tre lavoratori senza auto stanno nel gruppo con conteggio 3 (verificato in SQLite con GROUP BY Car).
Errore nel materiale del corso. La slide scrive e . Con la semantica SQL standard conta i valori non nulli, duplicati compresi, e vale 3; il valore 2 è quello di . Il del conteggio su due attributi coincide con il numero di coppie distinte (compresa quella con NULL), e in SQL non esiste un su più colonne senza
DISTINCTe parentesi di riga. I numeri della slide vanno letti come conteggi di valori distinti.
Versione ripasso
1. Incasso per pizza, totale e massimo. Proiezione generalizzata: dà (Margherita,80), (Capricciosa,200), (Funghi,18), (Marinara,78). Poi , perché .
- SQL:
SELECT SUM(Prezzo*Quantita) AS TotIncome, MAX(Prezzo*Quantita) AS MaxIncome FROM Pizzeria;
2. Incasso per sede. Il valore è calcolato e poi sommato su gruppo: 80, 220, 18, 78 per riga, poi . Vicenza , Padova . Grado , cardinalità 2 (due gruppi).
- SQL:
SELECT Sede, SUM(Prezzo*Quantita) AS Incasso FROM Pizzeria GROUP BY Sede;
3. Ristoranti: totale e media.
- Passo 1: , poi : R1 e ; R2 e ; R3 e .
- Errore del corso: la slide riporta 800, 1800, 2100, 1500 per le prime quattro righe.
- Massimo del totale: si aggrega il totale per ristorante, si prende il massimo e si fa join sul valore. Risultato .
4. NULL e aggregazione. Esami, con Mark NULL per 384752 (Analysis) e per 3841345:
- , , , (non ), , ;
- media per studente: 123456 dà 22,5; 384752 dà 18; 3841345, che ha solo NULL, dà NULL.
Lavoratori, con Car NULL per tre dei sei:
- ; (valori non nulli, duplicati compresi); ;
- dà (Volvo,1), (Fiat,2), (NULL,3): i NULL formano un gruppo unico.
- Errore del corso: la slide scrive , che è il valore di
COUNT(DISTINCT).
Errori tipici
- Dividere l'AVG per tutte le tuple anche con NULL.
- al posto di .
- Calcolare l'incasso dopo il raggruppamento invece che prima.