Algebra relazionale estesa - divisione, aggregazione e outer join
In questa pagina 10
Prerequisito: Algebra relazionale - operatori di base e joinLe operazioni sul modello relazionale sono di aggiornamento (inserimento, modifica, cancellazione, che possono violare i vincoli di integrità: si rifiuta, si corregge, si propaga con cascade o si imposta NULL/default) e di interrogazione (funzioni che da un'istanza del database producono una relazione). L'algebra relazionale è il linguaggio procedurale delle interrogazioni: gli operatori primitivi sono unione, differenza, prodotto, rinomina ρ, selezione σ e proiezione π; derivati sono intersezione, theta-join, equi-join, join naturale. Unione, intersezione e differenza richiedono relazioni compatibili all'unione (stessi attributi e domini). La selezione è una decomposizione orizzontale, la proiezione verticale (commutano solo se gli attributi della selezione sono nella proiezione). Il theta-join è σ_φ(R1×R2), il join naturale equivale a un equi-join sugli attributi omonimi seguito da una proiezione; la sua cardinalità è tra 0 e |R1||R2|, ≤|R1| se gli attributi comuni sono chiave di R2, =|R1| se sono anche chiave esterna di R1 con vincolo di integrità referenziale. Le tuple senza corrispondente sono "dangling". I valori NULL richiedono condizioni esplicite IS NULL / IS NOT NULL, perché σ_{A>40} ∪ σ_{A≤40} non restituisce le tuple con A nullo.Algebra relazionale - operatori di base e join →. Qui si estende l'algebra con quello che serve per le interrogazioni dei temi d'esame (somme, medie, massimi, "per ciascuno", "tutti"). La controparte in SQL è in SQL - interrogazioni, join e aggregazioniUn'interrogazione SQL ha almeno SELECT e FROM; le altre clausole (WHERE, GROUP BY, HAVING, ORDER BY) sono opzionali e HAVING richiede GROUP BY. Ordine logico di valutazione: FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY. SELECT corrisponde a π (ma senza DISTINCT non elimina i duplicati), WHERE a σ, gli alias ad AS/ρ, i join a ⋈ (INNER, LEFT, RIGHT, FULL). WHERE seleziona le righe prima del raggruppamento, HAVING seleziona i gruppi dopo. Le funzioni COUNT, SUM, AVG, MIN, MAX ignorano i NULL (COUNT(*) conta le righe, DISTINCT toglie i duplicati dentro la funzione); con un aggregato o con GROUP BY nella SELECT possono comparire solo colonne di raggruppamento o aggregati. LIKE usa % (qualsiasi sequenza) e _ (un carattere). I confronti con NULL non sono veri: serve IS NULL. Un filtro sulla tabella di destra di un LEFT JOIN va nella clausola ON, non in WHERE, altrimenti il join diventa interno. Con interi COUNT(a)/COUNT(b) è una divisione intera: serve CAST.SQL - interrogazioni, join e aggregazioni → e SQL - query nidificate, operatori insiemistici e visteUna sottoquery è una SELECT tra parentesi dentro un'altra: nella FROM (tabella derivata, con alias obbligatorio in PostgreSQL) oppure nella WHERE, come valore scalare con =, <, ..., come insieme con IN / NOT IN, ANY, ALL, oppure con EXISTS / NOT EXISTS. Una sottoquery correlata usa colonne della query esterna e va rivalutata per ogni riga. Le funzioni di aggregazione non si possono usare in WHERE: il massimo si ottiene con una sottoquery scalare (WHERE n = (SELECT MAX(n) ...)), con una vista o una CTE. NOT IN con una sottoquery che contiene NULL non restituisce mai righe: meglio NOT EXISTS, EXCEPT o LEFT JOIN ... IS NULL. "Per tutti" (divisione) = doppio NOT EXISTS o HAVING COUNT(DISTINCT ...) = numero totale. Gli operatori insiemistici UNION, INTERSECT, EXCEPT richiedono query compatibili e di default eliminano i duplicati (ALL li mantiene). Una vista è una tabella virtuale definita da una query (CREATE VIEW, DROP VIEW): semplifica le query, riusa sottoquery, nasconde i dati; la vista materializzata invece memorizza il risultato.SQL - query nidificate, operatori insiemistici e viste →; gli esercizi sono in Esercizio - Algebra relazionale estesa su pizzeria, ristoranti e conteggi con NULL (esercizi di algebra estesa del corso).
Perché serve un'estensione
Nell'algebra di base le operazioni valutano una tupla alla volta, indipendentemente dalle altre. Ma una query può chiedere informazioni che non sono memorizzate come valore di nessun attributo:
- "l'incasso di ogni tipo di pizza": serve calcolare prezzo per quantità, cioè operare tra attributi;
- "l'incasso di ogni sede": serve sommare su un gruppo di tuple.
Selezioni, proiezioni e join non bastano.
Proiezione generalizzata
Definizione. Data e funzioni sugli attributi di (attributi, costanti, espressioni aritmetiche),
Estende la proiezione: oltre a scegliere colonne, ne calcola di nuove. Con Pizzeria(Pizza, Prezzo, Quantita) = , , , :
La colonna calcolata non ha un nome: lo si dà con la rinomina, (è la notazione delle slide; in un compito si può scrivere direttamente , purché sia chiaro). Una proiezione generalizzata può produrre duplicati che poi spariscono: due tuple con gli stessi risultati diventano una sola.
Aggregazione
Le funzioni di aggregazione lavorano su insiemi di valori e non su singole tuple.
| Funzione | Calcola |
|---|---|
| somma dei valori di | |
| , | massimo, minimo dei valori di |
| media dei valori di | |
| numero di tuple (non di valori distinti) |
Definizione (aggregazione). Data e funzioni di aggregazione con , Il risultato è una relazione con attributi (uno per funzione) e esattamente una tupla: grado , cardinalità 1.
Esempio. "Incasso totale e incasso massimo" sui totali sopra, che chiamiamo
INCOME(Pizza, Totale): Gli attributi hanno nomi e ; per cambiarli: .
Raggruppamento
L'aggregazione globale riassume l'intera relazione. Spesso serve invece calcolare per ciascun gruppo: il gruppo è l'insieme di tuple con gli stessi valori su uno o più attributi.
Definizione (raggruppamento). Data , funzioni e attributi di raggruppamento , Gli attributi prima di sono quelli di raggruppamento. Il risultato ha grado e una tupla per ogni gruppo (cardinalità = numero di gruppi).
Esempio (ristoranti).
Restaurant(Name, Date, PriceMenu, Seats): , , , , . "Per ogni ristorante l'incasso totale e medio":
- dà , , , , ;
- dà , , .
Tre gruppi, tre tuple. Con attributi di raggruppamento si ricade nell'aggregazione globale (un solo gruppo).
Il raggruppamento si può scrivere in due passi, per leggibilità: prima la proiezione generalizzata che calcola il valore (INCOME), poi l'aggregazione.
NULL e funzioni di aggregazione
SUM, AVG, MAX, MIN ignorano i NULL: il risultato è calcolato solo sulle tuple con valore non nullo. Se tutti i valori sono NULL il risultato è NULL.
Con Exam(Student, Date, Mark, Course): , , , , :
- (conta le tuple, anche con NULL), (solo i voti non nulli);
- , (non ), , ;
- raggruppando per studente, la media dello studente , che ha solo NULL, è NULL.
Con Worker(Badge, Name, Surname, Car) e due tuple con la stessa auto NULL, i NULL formano un gruppo a sé: dà , , . In generale si perdono tuple solo se l'aggregato ignora il valore, mai per il raggruppamento.
Outer join
Nel join le tuple dangling spariscono. L'outer join le mantiene, completando con NULL gli attributi dell'altro operando.
Le slide usano i simboli ⟗, ⟕ e ⟖; qui si scrive , , per full, left e right.
- Full outer join : al theta-join aggiunge le tuple dangling di entrambi gli operandi;
- Left outer join : solo le tuple dangling di (sinistra);
- Right outer join : solo quelle di (destra).
Con Employee(Surname, Dep) = e Department(Code, Manager) = , è
| Surname | Dep | Code | Manager |
|---|---|---|---|
| Rossi | A | A | Mori |
| Neri | B | B | Bruni |
| Bianchi | B | B | Bruni |
| Neri | C | NULL | NULL |
| NULL | NULL | D | Verdi |
La riga è dangling a sinistra; a destra. Con il left join si ha solo la riga di Neri-C in più, con il right solo quella di Verdi.
L'outer join è un operatore derivato: si ottiene dal join con unione e differenza,
dove e sono gli attributi di e e il singoletto di NULL ha tanti NULL quanti gli attributi dell'altro operando (le slide scrivono i due pezzi come con l'insieme dei NULL, ma l'idea è questa). Si usa il left join quando serve "tutte le tuple di , anche quelle senza corrispondenza": per esempio "ogni post con il numero dei suoi commenti, anche zero".
NULL nella chiave di join. Se
Employeecontiene eDepartmentcontiene , le due tuple non si accoppiano (NULL NULL non è vero): nel full outer join compaiono entrambe, ciascuna completata con NULL.
Divisione
Definizione. Date e , la divisione ha schema e contiene le tuple tali che per ogni la tupla appartiene a :
La derivazione si legge così: contiene tutte le coppie possibili; togliendo restano le coppie che mancano; proiettando su si hanno gli che hanno almeno una coppia mancante; sottraendoli da restano quelli che non ne hanno nessuna.
Esempio.
Passed(Student, Course)= , , , , , , , , , eCourse(Course)= . "Gli studenti che hanno superato tutti gli esami del primo anno":
- ha coppie;
- meno restano le coppie mancanti: , , , ;
- proiettando: Bruno e Dario hanno qualcosa di mancante;
- risultato: .
Carla ha superato anche
Algebra, che non è inCourse: non conta, la divisione chiede tutti quelli di , non solo quelli.
La divisione non è tra gli operatori delle slide del corso, che risolvono i "per tutti" con la differenza (il complemento della nota precedente); la formula è equivalente. In SQL non esiste un operatore: si usa il doppio NOT EXISTS o un conteggio con HAVING (SQL - query nidificate, operatori insiemistici e visteUna sottoquery è una SELECT tra parentesi dentro un'altra: nella FROM (tabella derivata, con alias obbligatorio in PostgreSQL) oppure nella WHERE, come valore scalare con =, <, ..., come insieme con IN / NOT IN, ANY, ALL, oppure con EXISTS / NOT EXISTS. Una sottoquery correlata usa colonne della query esterna e va rivalutata per ogni riga. Le funzioni di aggregazione non si possono usare in WHERE: il massimo si ottiene con una sottoquery scalare (WHERE n = (SELECT MAX(n) ...)), con una vista o una CTE. NOT IN con una sottoquery che contiene NULL non restituisce mai righe: meglio NOT EXISTS, EXCEPT o LEFT JOIN ... IS NULL. "Per tutti" (divisione) = doppio NOT EXISTS o HAVING COUNT(DISTINCT ...) = numero totale. Gli operatori insiemistici UNION, INTERSECT, EXCEPT richiedono query compatibili e di default eliminano i duplicati (ALL li mantiene). Una vista è una tabella virtuale definita da una query (CREATE VIEW, DROP VIEW): semplifica le query, riusa sottoquery, nasconde i dati; la vista materializzata invece memorizza il risultato.SQL - query nidificate, operatori insiemistici e viste →).
Ricette per i casi tipici
| La richiesta dice | Schema dell'espressione |
|---|---|
| "per ciascun il numero / la somma / la media di..." | raggruppamento (dopo i join che portano insieme gli attributi) |
| "il con il massimo di..." | (1) per ogni ; (2) ; (3) |
| "tutti i... che..." | divisione, oppure tutti quelli per cui esiste un controesempio |
| "almeno due..." | self-join con rinomina e condizione (o raggruppamento con ) |
| "nessuno..." / "che non..." | tutti quelli che hanno almeno uno (differenza) |
| "anche quelli senza..." | outer join, poi eventuale raggruppamento con su un attributo dell'operando destro |
Sul massimo: nella terza fase si confrontano due attributi dopo un join (o un prodotto) tra e ; scrivere con una relazione è un'abbreviazione imprecisa. Se il massimo non è unico, la tecnica restituisce tutti i massimi, come è giusto; ordinare e prendere il primo (LIMIT 1 in SQL) ne restituirebbe uno solo.
Errori tipici
- Confondere (tuple) con (valori non nulli); aspettarsi che AVG divida per tutte le tuple anche con NULL.
- Mettere nel risultato di un raggruppamento attributi che non sono né di raggruppamento né aggregati.
- Dimenticare di rinominare il risultato di un'aggregazione prima di usarlo in un join.
- Fare il join prima del raggruppamento e moltiplicare i duplicati: contare dopo il join conta le tuple del join, non quelle di partenza.
- Usare un join interno dove servivano anche i "senza corrispondenza" (conteggi che dovevano dare zero).
- Dividere per vuoto: è tutto (ogni soddisfa il "per ogni" vuoto).
Domande d'esame
1. Come si esprime in algebra relazionale "per ogni brano il numero totale di ascolti", e quanto vale grado e cardinalità del risultato? Traccia. : grado (un attributo di raggruppamento e un aggregato), cardinalità pari al numero di brani con almeno un ascolto.
2. Cosa cambia tra left join e inner join per contare i commenti di ogni post? Traccia. L'inner join perde i post senza commenti; il left join li mantiene con NULL, e (non !) dà 0 per quei post.
3. Scrivere con la divisione . Traccia. : tutti gli meno quelli per cui manca almeno una coppia .
Versione ripasso
Perché: l'algebra di base valuta una tupla alla volta. Servono le estensioni per calcolare valori tra attributi (incasso = prezzo per quantità), sommare su gruppi e per i "per tutti" (Algebra relazionale - operatori di base e joinLe operazioni sul modello relazionale sono di aggiornamento (inserimento, modifica, cancellazione, che possono violare i vincoli di integrità: si rifiuta, si corregge, si propaga con cascade o si imposta NULL/default) e di interrogazione (funzioni che da un'istanza del database producono una relazione). L'algebra relazionale è il linguaggio procedurale delle interrogazioni: gli operatori primitivi sono unione, differenza, prodotto, rinomina ρ, selezione σ e proiezione π; derivati sono intersezione, theta-join, equi-join, join naturale. Unione, intersezione e differenza richiedono relazioni compatibili all'unione (stessi attributi e domini). La selezione è una decomposizione orizzontale, la proiezione verticale (commutano solo se gli attributi della selezione sono nella proiezione). Il theta-join è σ_φ(R1×R2), il join naturale equivale a un equi-join sugli attributi omonimi seguito da una proiezione; la sua cardinalità è tra 0 e |R1||R2|, ≤|R1| se gli attributi comuni sono chiave di R2, =|R1| se sono anche chiave esterna di R1 con vincolo di integrità referenziale. Le tuple senza corrispondente sono "dangling". I valori NULL richiedono condizioni esplicite IS NULL / IS NOT NULL, perché σ_{A>40} ∪ σ_{A≤40} non restituisce le tuple con A nullo.Algebra relazionale - operatori di base e join →).
Proiezione generalizzata: . Con Pizzeria(Pizza, Prezzo, Quantita): dà (Margherita,80), (Capricciosa,200), (Funghi,18), (Marinara,78). La colonna calcolata si nomina con .
Aggregazione : esattamente una tupla, grado . Funzioni: SUM, MAX, MIN, AVG, COUNT. Sui totali sopra, dà .
Raggruppamento : grado , una tupla per gruppo. Esempio ristoranti, con calcolato prima con :
- : (R1,10/12,8000), (R2,10/12,18000), (R2,11/12,21000), (R1,11/12,15000), (R3,11/12,4200);
- : (R1,23000,11500), (R2,39000,19500), (R3,4200,4200).
NULL e aggregati
- SUM, AVG, MAX, MIN ignorano i NULL; se sono tutti NULL il risultato è NULL.
- Con
Exam(Student, Date, Mark, Course)e cinque tuple, due conMarkNULL: , , , (non ), , . - Nel raggruppamento i NULL formano un gruppo a sé.
Outer join
- Full : join più dangling di entrambi i lati; left : solo di ; right : solo di . I dangling si completano con NULL.
- Esempio:
Employee(Surname, Dep)= (Rossi,A), (Neri,B), (Bianchi,B), (Neri,C) eDepartment(Code, Manager)= (A,Mori), (B,Bruni), (D,Verdi). Il full outer join ha cinque righe: le tre del join, (Neri,C,NULL,NULL) e (NULL,NULL,D,Verdi). - NULL nella chiave di join non si accoppiano.
Divisione .
- Esempio:
Passed(Student, Course)eCourse= {Analisi, Fisica, BD}. Bruno e Dario hanno almeno un esame mancante, quindi . Carla ha anche Algebra, che non è inCourse: non conta. - In SQL non c'è l'operatore: si usa il doppio
NOT EXISTSoHAVING COUNT(SQL - query nidificate, operatori insiemistici e visteUna sottoquery è una SELECT tra parentesi dentro un'altra: nella FROM (tabella derivata, con alias obbligatorio in PostgreSQL) oppure nella WHERE, come valore scalare con =, <, ..., come insieme con IN / NOT IN, ANY, ALL, oppure con EXISTS / NOT EXISTS. Una sottoquery correlata usa colonne della query esterna e va rivalutata per ogni riga. Le funzioni di aggregazione non si possono usare in WHERE: il massimo si ottiene con una sottoquery scalare (WHERE n = (SELECT MAX(n) ...)), con una vista o una CTE. NOT IN con una sottoquery che contiene NULL non restituisce mai righe: meglio NOT EXISTS, EXCEPT o LEFT JOIN ... IS NULL. "Per tutti" (divisione) = doppio NOT EXISTS o HAVING COUNT(DISTINCT ...) = numero totale. Gli operatori insiemistici UNION, INTERSECT, EXCEPT richiedono query compatibili e di default eliminano i duplicati (ALL li mantiene). Una vista è una tabella virtuale definita da una query (CREATE VIEW, DROP VIEW): semplifica le query, riusa sottoquery, nasconde i dati; la vista materializzata invece memorizza il risultato.SQL - query nidificate, operatori insiemistici e viste →).
Ricette
| La richiesta dice | Schema |
|---|---|
| "per ciascun il numero / la somma / la media" | raggruppamento , dopo i join |
| "il con il massimo di " | (1) ; (2) ; (3) |
| "tutti i... che..." | divisione, oppure tutti meno quelli con un controesempio |
| "almeno due" | self-join con rinomina e , oppure |
| "nessuno" | tutti meno quelli che hanno almeno uno |
| "anche quelli senza..." | outer join, poi su un attributo del lato destro |
Nel massimo il confronto avviene dopo un join. Se il massimo non è unico la tecnica restituisce tutti i massimi; LIMIT 1 ne darebbe uno solo.
Errori tipici
- Confondere con ; aspettarsi che AVG divida per tutte le tuple.
- Join prima del raggruppamento: moltiplica le tuple e il conteggio è sbagliato.
- Join interno dove servono i "senza corrispondenza" (conteggi che devono dare zero: si usa , non ).
- è tutto .
Esercizi: Esercizio - Algebra relazionale estesa su pizzeria, ristoranti e conteggi con NULL (esercizi di algebra estesa del corso). In SQL: SQL - interrogazioni, join e aggregazioniUn'interrogazione SQL ha almeno SELECT e FROM; le altre clausole (WHERE, GROUP BY, HAVING, ORDER BY) sono opzionali e HAVING richiede GROUP BY. Ordine logico di valutazione: FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY. SELECT corrisponde a π (ma senza DISTINCT non elimina i duplicati), WHERE a σ, gli alias ad AS/ρ, i join a ⋈ (INNER, LEFT, RIGHT, FULL). WHERE seleziona le righe prima del raggruppamento, HAVING seleziona i gruppi dopo. Le funzioni COUNT, SUM, AVG, MIN, MAX ignorano i NULL (COUNT(*) conta le righe, DISTINCT toglie i duplicati dentro la funzione); con un aggregato o con GROUP BY nella SELECT possono comparire solo colonne di raggruppamento o aggregati. LIKE usa % (qualsiasi sequenza) e _ (un carattere). I confronti con NULL non sono veri: serve IS NULL. Un filtro sulla tabella di destra di un LEFT JOIN va nella clausola ON, non in WHERE, altrimenti il join diventa interno. Con interi COUNT(a)/COUNT(b) è una divisione intera: serve CAST.SQL - interrogazioni, join e aggregazioni →.
Esercizi su questo argomento
- Esercizio - Algebra relazionale estesa su pizzeria, ristoranti e conteggi con NULL (esercizi di algebra estesa del corso)
- Esercizio - Algebra relazionale su impiegati e dirigenti (esercizi di algebra relazionale del corso)
- Esercizio - Interrogazioni sugli ordini di una pizzeria (tema d'esame 1 marzo 2013)
- Esercizio - Interrogazioni sulla compagnia di treni (tema d'esame 17 giugno 2013)
- Esercizio - Interrogazioni sulla mensa universitaria (tema d'esame 13 febbraio 2012)
- Esercizio - Interrogazioni sulla piattaforma di streaming musicale (tema d'esame 12 febbraio 2024)
- Esercizio - Interrogazioni sullo stabilimento balneare (tema d'esame 18 giugno 2012)