Salta al contenuto
Note per Studenti Esercizio - Algebra relazionale su impiegati e dirigenti (esercizi di algebra relazionale del corso)

Esercizio - Algebra relazionale su impiegati e dirigenti (esercizi di algebra relazionale del corso)

In questa pagina 11

Testo (esercizi di algebra relazionale del corso di Basi di Dati, Ing. Informatica UniPD). Dato lo schema

  • Employee(Badge, Surname, Age, Salary), chiave Badge;
  • Manage(Employee, Manager), chiave Employee, con Employee e Manager chiavi esterne verso Employee.Badge (a ogni impiegato corrisponde al più un dirigente)

e l'istanza

Employee: Badge Surname Age Salary
7309 Rossi 34 45
5998 Bianchi 37 38
9553 Neri 42 35
5698 Bruni 43 42
4076 Mori 45 50
8123 Lupi 46 60
Manage: Employee Manager
7309 5698
5998 5698
9553 4076
5698 4076
4076 8123

scrivere in algebra relazionale:

  1. badge, cognome, età e stipendio degli impiegati che guadagnano più di 42;
  2. badge, cognome ed età degli impiegati che guadagnano più di 42;
  3. il badge dei dirigenti i cui impiegati guadagnano più di 42;
  4. cognome e stipendio dei dirigenti i cui impiegati guadagnano più di 42;
  5. cognome e stipendio dei dirigenti che guadagnano più di 45;
  6. gli impiegati che guadagnano più del proprio dirigente, con badge, cognome e stipendio di entrambi;
  7. il badge dei dirigenti i cui impiegati guadagnano tutti più di 42;
  8. il badge dei dirigenti che a loro volta hanno un dirigente.

Teoria: 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 →. Estensioni: Algebra relazionale estesa - divisione, aggregazione e outer joinL'algebra relazionale di base lavora una tupla alla volta e non sa fare calcoli sui valori né riassumere più tuple. L'estensione aggiunge: la proiezione generalizzata π_{F1,...,Fn}(R), che calcola espressioni sugli attributi (prezzo per quantità); l'aggregazione ℱ_{SUM, MAX, MIN, AVG, COUNT}(R), che produce una sola tupla; il raggruppamento (A1,...,Am)ℱ_{f(B)}(R), che produce una tupla per gruppo (grado n+m, cardinalità = numero di gruppi). Le funzioni di aggregazione ignorano i NULL, COUNT(*) conta le tuple, i NULL formano un gruppo a sé. Gli outer join (left, right, full) mantengono con NULL le tuple dangling del join; i NULL nella chiave di join non si accoppiano mai. La divisione R÷S dà gli x tali che (x,y) sta in R per ogni y di S, e si ottiene con π, × e −. Ricette: massimo = aggregazione + join con il massimo, "tutti" = divisione o complemento, "almeno due" = self-join.Algebra relazionale estesa - divisione, aggregazione e outer join →. Ogni espressione è stata valutata con un piccolo interprete di algebra su queste tabelle e confrontata con l'equivalente SQL provato con SQLite: i risultati sotto coincidono.


Esercizio 1

Una selezione basta: si tengono le tuple con Salary>42\text{Salary}>42, schema invariato.

σSalary>42(Employee)\sigma_{\text{Salary}>42}(\text{Employee})

Badge Surname Age Salary
7309 Rossi 34 45
4076 Mori 45 50
8123 Lupi 46 60

(Bruni guadagna esattamente 42: non è "più di 42".) SQL: SELECT * FROM Employee WHERE Salary > 42;. È una decomposizione orizzontale: si sceglie un sottoinsieme di righe.

Esercizio 2

Si aggiunge una proiezione: si scelgono le colonne. Si valuta dall'interno, prima la selezione.

πBadge,Surname,Age(σSalary>42(Employee))\pi_{\text{Badge},\text{Surname},\text{Age}}\big(\sigma_{\text{Salary}>42}(\text{Employee})\big)

Badge Surname Age
7309 Rossi 34
4076 Mori 45
8123 Lupi 46

Perché l'ordine conta. Se si proietta per primi, πBadge,Surname,Age(Employee)\pi_{\text{Badge},\text{Surname},\text{Age}}(\text{Employee}) non ha più Salary, e σSalary>42\sigma_{\text{Salary}>42} non si può applicare: errore. Selezione e proiezione commutano solo se gli attributi della selezione sono tra quelli proiettati (qui non lo sono).

Esercizio 3

Il dirigente sta in Manage, lo stipendio dell'impiegato in Employee: serve un join tra Employee = Badge. Conviene prima selezionare gli impiegati ricchi (relazione piccola) e poi fare il join:

πManager(Manage⋈Employee=BadgeσSalary>42(Employee))\pi_{\text{Manager}}\Big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\sigma_{\text{Salary}>42}(\text{Employee})\Big)

Passi:

  1. σSalary>42(Employee)\sigma_{\text{Salary}>42}(\text{Employee}): Rossi (7309), Mori (4076), Lupi (8123);
  2. il join con Manage tiene le tuple di Manage il cui Employee è uno di questi badge: (7309,5698)(7309,5698) e (4076,8123)(4076,8123). L'impiegato 8123 non compare in Manage.Employee (è il vertice): non ha corrispondente, la sua tupla di Employee è dangling e sparisce. È l'approccio basato sui valori del modello relazionale: ci si collega solo uguagliando valori;
  3. πManager\pi_{\text{Manager}} dà {5698,8123}\{5698, 8123\}.
Manager
5698
8123

Si può fare prima il join e poi la selezione (stesso risultato), ma il join lavora su più tuple: meno efficiente. Per il join è un equi-join, non un join naturale: gli attributi hanno nomi diversi (Employee e Badge). SQL:

sql
SELECT DISTINCT Manager
FROM Manage m JOIN Employee e ON m.Employee = e.Badge
WHERE e.Salary > 42;

Il DISTINCT corrisponde al fatto che la proiezione algebrica elimina i duplicati (un dirigente con due impiegati ricchi comparirebbe due volte).

Esercizio 4

Ora servono i dati del dirigente (cognome, stipendio): ci vuole un secondo join con Employee, che va però rinominata per non confondere l'impiegato con il dirigente.

Soluzione 1 (la prima del corso). Si rinomina la selezione sugli impiegati ricchi:

R1←ρE.Bdg,E.Srn,E.Age,E.Slry←Badge,Surname,Age,Salary(σSalary>42(Employee))R_1\leftarrow\rho_{\text{E.Bdg},\text{E.Srn},\text{E.Age},\text{E.Slry}\leftarrow\text{Badge},\text{Surname},\text{Age},\text{Salary}}\big(\sigma_{\text{Salary}>42}(\text{Employee})\big) R2←Manage⋈Employee=E.BdgR1R3←Employee⋈Badge=ManagerR2R_2\leftarrow\text{Manage}\bowtie_{\text{Employee}=\text{E.Bdg}}R_1\qquad R_3\leftarrow\text{Employee}\bowtie_{\text{Badge}=\text{Manager}}R_2 πSurname,Salary(R3)\pi_{\text{Surname},\text{Salary}}(R_3)

R2R_2 contiene (5698,7309,…,Rossi)(5698,7309,\dots,\text{Rossi}) e (8123,4076,…,Mori)(8123,4076,\dots,\text{Mori}) (due tuple: le coppie dirigente-impiegato ricco). R3R_3 abbina a ciascuna il dirigente (Badge = Manager): Bruni (5698) e Lupi (8123). Il risultato:

Surname Salary
Bruni 42
Lupi 60

Soluzione 2 (equivalente, più corta, per eliminare la rinomina): si riusa il risultato dell'esercizio 3, che contiene già solo i badge dei dirigenti,

πSurname,Salary(Employee⋈Badge=ManagerπManager(Manage⋈Employee=BadgeσSalary>42(Employee)))\pi_{\text{Surname},\text{Salary}}\Big(\text{Employee}\bowtie_{\text{Badge}=\text{Manager}}\pi_{\text{Manager}}\big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\sigma_{\text{Salary}>42}(\text{Employee})\big)\Big)

Nessuna rinomina è necessaria perché Manager e Badge sono nomi diversi e la parte interna ha solo l'attributo Manager. È il consiglio generale: si proietta via ciò che non serve appena possibile. SQL:

sql
SELECT DISTINCT m.Surname, m.Salary
FROM Employee m JOIN Manage g ON g.Manager = m.Badge
                JOIN Employee e ON e.Badge = g.Employee
WHERE e.Salary > 42;

Qui compaiono due volte Employee con alias m (manager) ed e (impiegato): in SQL la rinomina è l'alias.

Esercizio 5

Chiede i dirigenti con stipendio >45>45: si seleziona su Employee come dirigente e si collega con Manage.Manager.

πSurname,Salary(Manage⋈Manager=BadgeσSalary>45(Employee))\pi_{\text{Surname},\text{Salary}}\Big(\text{Manage}\bowtie_{\text{Manager}=\text{Badge}}\sigma_{\text{Salary}>45}(\text{Employee})\Big)

  1. σSalary>45\sigma_{\text{Salary}>45}: Mori (50) e Lupi (60);
  2. il join con Manage su Manager = Badge dà tre tuple: (9553,4076)(9553,4076), (5698,4076)(5698,4076), (4076,8123)(4076,8123): Mori compare due volte perché ha due impiegati (approccio basato sui valori: ogni corrispondenza genera una tupla);
  3. la proiezione su (Surname,Salary)(\text{Surname},\text{Salary}) rende uguali le due tuple di Mori e, essendo una relazione un insieme, ne resta una.
Surname Salary
Mori 50
Lupi 60

Il join con Manage serve a restringere ai soli dirigenti: σSalary>45(Employee)\sigma_{\text{Salary}>45}(\text{Employee}) da sola contiene chiunque guadagni più di 45, anche chi non dirige nessuno (nei dati dati sono tutti dirigenti, ma in generale no). Qui non servono i dati degli impiegati, solo la loro esistenza come "dirigente di qualcuno": a differenza dell'esercizio 4, quindi, non serve alcuna rinomina. SQL: SELECT DISTINCT e.Surname, e.Salary FROM Manage m JOIN Employee e ON m.Manager = e.Badge WHERE e.Salary > 45;.

Esercizio 6

Servono due copie di Employee (impiegato e dirigente) e un confronto tra i loro stipendi: un self-join con rinomina e un theta-join (la condizione >> non è un'uguaglianza).

Soluzione 1 (equi-join e poi selezione):

πBadge,Surname,Salary,M.Bdg,M.Srn,M.Slry(σSalary>M.Slry(Manage⋈Employee=BadgeEmployee⋈M.Bdg=ManagerρM.Bdg,M.Srn,M.Age,M.Slry←Badge,Surname,Age,Salary(Employee)))\pi_{\text{Badge},\text{Surname},\text{Salary},\text{M.Bdg},\text{M.Srn},\text{M.Slry}}\Big(\sigma_{\text{Salary}>\text{M.Slry}}\big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\text{Employee}\bowtie_{\text{M.Bdg}=\text{Manager}}\rho_{\text{M.Bdg},\text{M.Srn},\text{M.Age},\text{M.Slry}\leftarrow\text{Badge},\text{Surname},\text{Age},\text{Salary}}(\text{Employee})\big)\Big)

Soluzione 2 (theta-join, evita la selezione dopo l'equi-join):

π…(Manage⋈Employee=BadgeEmployee ⋈M.Bdg=Manager ∧ Salary>M.Slry ρM.Bdg,⋯←Badge,…(Employee))\pi_{\dots}\Big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\text{Employee}\ \bowtie_{\text{M.Bdg}=\text{Manager}\ \wedge\ \text{Salary}>\text{M.Slry}}\ \rho_{\text{M.Bdg},\dots\leftarrow\text{Badge},\dots}(\text{Employee})\Big)

Passi: il primo join associa a ogni impiegato la riga di Manage (5 tuple); il secondo aggancia a ogni riga il dirigente (la copia rinominata), e la condizione Salary>M.Slry\text{Salary}>\text{M.Slry} tiene le coppie in cui l'impiegato guadagna più del dirigente. Le cinque coppie (impiegato con stipendio, dirigente con stipendio) sono: Rossi 45 e Bruni 42 (sì), Bianchi 38 e Bruni 42, Neri 35 e Mori 50, Bruni 42 e Mori 50, Mori 50 e Lupi 60 (no, in tutti gli altri casi). Unico risultato:

Badge Surname Salary M.Bdg M.Srn M.Slry
7309 Rossi 45 5698 Bruni 42

SQL:

sql
SELECT e.Badge, e.Surname, e.Salary, m.Badge, m.Surname, m.Salary
FROM Manage g JOIN Employee e ON g.Employee = e.Badge
              JOIN Employee m ON g.Manager = m.Badge
WHERE e.Salary > m.Salary;

Esercizio 7

"Tutti gli impiegati guadagnano più di 42" è una condizione universale: l'algebra non ha il ∀\forall, ma si usa il complemento: tutti i dirigenti meno quelli per cui esiste un impiegato con stipendio ≤42\le42 (il contrario di ">42>42" è "≤42\le42").

πManager(Manage) − πManager(Manage⋈Employee=BadgeσSalary≤42(Employee))\pi_{\text{Manager}}(\text{Manage})\ -\ \pi_{\text{Manager}}\Big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\sigma_{\text{Salary}\le42}(\text{Employee})\Big)

  1. R12←πManager(Manage)={5698,4076,8123}R_{12}\leftarrow\pi_{\text{Manager}}(\text{Manage})=\{5698,4076,8123\}: tutti i dirigenti;
  2. σSalary≤42(Employee)\sigma_{\text{Salary}\le42}(\text{Employee}): Bianchi (38), Neri (35), Bruni (42);
  3. il join con Manage dà le coppie (5998,5698)(5998,5698), (9553,4076)(9553,4076), (5698,4076)(5698,4076), la cui proiezione su Manager è {5698,4076}\{5698,4076\}: i dirigenti con almeno un impiegato "povero";
  4. la differenza lascia {8123}\{8123\}: Lupi dirige solo Mori (50).
Manager
8123

Un errore tipico è dimenticare che la prima parte deve essere "i dirigenti" e non tutti gli impiegati: un impiegato che non dirige nessuno soddisfarebbe vacuamente il "tutti". SQL con EXCEPT: SELECT DISTINCT Manager FROM Manage EXCEPT SELECT m.Manager FROM Manage m JOIN Employee e ON m.Employee = e.Badge WHERE e.Salary <= 42;.

Esercizio 8

Un dirigente che a sua volta ha un dirigente è un badge che compare sia come Manager sia come Employee in Manage.

Soluzione 1 (self-join con rinomina). Si accoppia Manage con una sua copia, dove l'impiegato della copia deve coincidere con il dirigente della prima; la copia va rinominata per intero (anche Manager, altrimenti ci sarebbero due attributi con lo stesso nome):

πManager(Manage⋈Manager=E2ρE2,M2←Employee,Manager(Manage))\pi_{\text{Manager}}\Big(\text{Manage}\bowtie_{\text{Manager}=\text{E2}}\rho_{\text{E2},\text{M2}\leftarrow\text{Employee},\text{Manager}}(\text{Manage})\Big)

Le tuple che si accoppiano sono quelle in cui il dirigente della prima è impiegato della seconda: 5698 (è impiegato con dirigente 4076) e 4076 (con dirigente 8123). Il risultato {5698,4076}\{5698,4076\}.

Soluzione 2 (intersezione di due proiezioni, rese compatibili con la rinomina):

ρWithMgr←Manager(πManager(Manage)) ∩ ρWithMgr←Employee(πEmployee(Manage))\rho_{\text{WithMgr}\leftarrow\text{Manager}}\big(\pi_{\text{Manager}}(\text{Manage})\big)\ \cap\ \rho_{\text{WithMgr}\leftarrow\text{Employee}}\big(\pi_{\text{Employee}}(\text{Manage})\big)

I dirigenti {5698,4076,8123}\{5698,4076,8123\} intersecati con gli impiegati {7309,5998,9553,5698,4076}\{7309,5998,9553,5698,4076\} danno {5698,4076}\{5698,4076\}. È la forma più leggibile.

WithMgr
4076
5698

Errore da evitare: σManager=Employee(Manage)\sigma_{\text{Manager}=\text{Employee}}(\text{Manage}). Confronta i due attributi nella stessa tupla, cioè cerca chi dirige se stesso, e restituisce la relazione vuota (verificato). Il collegamento tra "il dirigente di una riga" e "l'impiegato di un'altra riga" richiede un join della relazione con una sua copia.

SQL: SELECT DISTINCT a.Manager FROM Manage a JOIN Manage b ON a.Manager = b.Employee;.


Altri esercizi sullo stesso schema

9. I badge degli impiegati che non hanno un dirigente (nessuno li dirige). "Che non" = differenza:

πBadge(Employee)−ρBadge←Employee(πEmployee(Manage))={8123}\pi_{\text{Badge}}(\text{Employee})-\rho_{\text{Badge}\leftarrow\text{Employee}}\big(\pi_{\text{Employee}}(\text{Manage})\big)=\{8123\}

10. I dirigenti con almeno due impiegati. Self-join di Manage con la copia rinominata e la condizione sugli impiegati diversi:

πManager(Manage⋈Manager=M2 ∧ Employee≠E2ρE2,M2←Employee,Manager(Manage))={5698,4076}\pi_{\text{Manager}}\Big(\text{Manage}\bowtie_{\text{Manager}=\text{M2}\ \wedge\ \text{Employee}\neq\text{E2}}\rho_{\text{E2},\text{M2}\leftarrow\text{Employee},\text{Manager}}(\text{Manage})\Big)=\{5698,4076\}

(Con l'algebra estesa: si raggruppa Manage per Manager, si conta e si tengono i gruppi con conteggio almeno 2.)

11. Stipendio medio degli impiegati di ciascun dirigente (algebra estesa): ManagerFAVG(Salary)(Manage⋈Employee=BadgeEmployee)_{\text{Manager}}\mathcal{F}_{\text{AVG}(\text{Salary})}\big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\text{Employee}\big) dà (4076;38,5)(4076;38{,}5), (5698;41,5)(5698;41{,}5), (8123;50)(8123;50) (verificato anche in SQL con GROUP BY Manager).

12. L'impiegato con lo stipendio massimo. M←ρm←MAX(Salary)(FMAX(Salary)(Employee))M\leftarrow\rho_{m\leftarrow\text{MAX}(\text{Salary})}\big(\mathcal{F}_{\text{MAX}(\text{Salary})}(\text{Employee})\big) e πBadge,Surname(Employee⋈Salary=mM)={(8123,Lupi)}\pi_{\text{Badge},\text{Surname}}(\text{Employee}\bowtie_{\text{Salary}=m}M)=\{(8123,\text{Lupi})\}.

Valori nulli e outer join: un esempio

Con Employee(Badge, Surname, Age, Branch) = (7309,Rossi,34,Roma)(7309,\text{Rossi},34,\text{Roma}), (5998,Bianchi,42,Milano)(5998,\text{Bianchi},42,\text{Milano}), (9553,Neri,NULL,Milano)(9553,\text{Neri},\text{NULL},\text{Milano}): σAge>40\sigma_{\text{Age}>40} dà Bianchi, σAge≤40\sigma_{\text{Age}\le40} dà Rossi, e la loro unione non è la relazione di partenza: Neri manca. Per recuperarla si aggiunge σAge IS NULL\sigma_{\text{Age IS NULL}}. Con Employee(Surname, Dep) e Department(Code, Manager) della nota di teoria, il full outer join ⋈Dep=CodeF\bowtie^{\text{F}}_{\text{Dep}=\text{Code}} aggiunge a 3 tuple di join le tuple dangling (Neri,C,NULL,NULL)(\text{Neri},C,\text{NULL},\text{NULL}) e (NULL,NULL,D,Verdi)(\text{NULL},\text{NULL},D,\text{Verdi}): 5 tuple in tutto, come visto in Algebra relazionale estesa - divisione, aggregazione e outer joinL'algebra relazionale di base lavora una tupla alla volta e non sa fare calcoli sui valori né riassumere più tuple. L'estensione aggiunge: la proiezione generalizzata π_{F1,...,Fn}(R), che calcola espressioni sugli attributi (prezzo per quantità); l'aggregazione ℱ_{SUM, MAX, MIN, AVG, COUNT}(R), che produce una sola tupla; il raggruppamento (A1,...,Am)ℱ_{f(B)}(R), che produce una tupla per gruppo (grado n+m, cardinalità = numero di gruppi). Le funzioni di aggregazione ignorano i NULL, COUNT(*) conta le tuple, i NULL formano un gruppo a sé. Gli outer join (left, right, full) mantengono con NULL le tuple dangling del join; i NULL nella chiave di join non si accoppiano mai. La divisione R÷S dà gli x tali che (x,y) sta in R per ogni y di S, e si ottiene con π, × e −. Ricette: massimo = aggregazione + join con il massimo, "tutti" = divisione o complemento, "almeno due" = self-join.Algebra relazionale estesa - divisione, aggregazione e outer join →.

Errori nel materiale del corso

  • Nella scheda a mano la riga di Mori compare con stipendio 60 in alcune tabelle intermedie degli esercizi 3 e 4 (per esempio nel passo "σSalary>42\sigma_{\text{Salary}>42}"), mentre nella tabella Employee vale 50: è un refuso di trascrizione. I risultati finali non cambiano. Nello stesso passo, un'etichetta riporta Salary>43\text{Salary}>43 invece di >42>42.
  • Nella soluzione 1 dell'esercizio 8 (slide sull'algebra) la rinomina ρWithMgr←Employee(Manage)\rho_{\text{WithMgr}\leftarrow\text{Employee}}(\text{Manage}) lascia due attributi chiamati Manager nel join (quello di Manage e quello della copia): la scheda annota "Manager dovrebbe essere rinominato insieme a Employee, ma...". Va rinominata anche la seconda colonna, come qui sopra.

Versione ripasso

Schema: Employee(Badge, Surname, Age, Salary) e Manage(Employee, Manager), entrambi con badge. Teoria: 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 →, Algebra relazionale estesa - divisione, aggregazione e outer joinL'algebra relazionale di base lavora una tupla alla volta e non sa fare calcoli sui valori né riassumere più tuple. L'estensione aggiunge: la proiezione generalizzata π_{F1,...,Fn}(R), che calcola espressioni sugli attributi (prezzo per quantità); l'aggregazione ℱ_{SUM, MAX, MIN, AVG, COUNT}(R), che produce una sola tupla; il raggruppamento (A1,...,Am)ℱ_{f(B)}(R), che produce una tupla per gruppo (grado n+m, cardinalità = numero di gruppi). Le funzioni di aggregazione ignorano i NULL, COUNT(*) conta le tuple, i NULL formano un gruppo a sé. Gli outer join (left, right, full) mantengono con NULL le tuple dangling del join; i NULL nella chiave di join non si accoppiano mai. La divisione R÷S dà gli x tali che (x,y) sta in R per ogni y di S, e si ottiene con π, × e −. Ricette: massimo = aggregazione + join con il massimo, "tutti" = divisione o complemento, "almeno due" = self-join.Algebra relazionale estesa - divisione, aggregazione e outer join →.

  1. σSalary>42(Employee)\sigma_{\text{Salary}>42}(\text{Employee}): Rossi (7309), Mori (4076), Lupi (8123). Bruni guadagna 42, quindi è escluso.
  2. πBadge,Surname,Age(σSalary>42(Employee))\pi_{\text{Badge},\text{Surname},\text{Age}}\big(\sigma_{\text{Salary}>42}(\text{Employee})\big). L'ordine conta: proiettando prima, Salary non esiste più.
  3. πManager(Manage⋈Employee=BadgeσSalary>42(Employee))={5698,8123}\pi_{\text{Manager}}\big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\sigma_{\text{Salary}>42}(\text{Employee})\big)=\{5698,8123\}. È un equi-join, non naturale, perché i nomi sono diversi. Lupi (8123) non compare in Manage.Employee: la sua tupla è dangling.
    • SQL: SELECT DISTINCT Manager FROM Manage m JOIN Employee e ON m.Employee = e.Badge WHERE e.Salary > 42;
  4. Cognome e stipendio dei dirigenti: πSurname,Salary(Employee⋈Badge=ManagerπManager(… ))={(Bruni,42),(Lupi,60)}\pi_{\text{Surname},\text{Salary}}\big(\text{Employee}\bowtie_{\text{Badge}=\text{Manager}}\pi_{\text{Manager}}(\dots)\big)=\{(\text{Bruni},42),(\text{Lupi},60)\}. Per riusare il risultato del punto 3 non serve una rinomina. Nella versione con la copia rinominata ρE.Bdg,…\rho_{\text{E.Bdg},\dots} la rinomina è obbligatoria.
  5. πSurname,Salary(Manage⋈Manager=BadgeσSalary>45(Employee))={(Mori,50),(Lupi,60)}\pi_{\text{Surname},\text{Salary}}\big(\text{Manage}\bowtie_{\text{Manager}=\text{Badge}}\sigma_{\text{Salary}>45}(\text{Employee})\big)=\{(\text{Mori},50),(\text{Lupi},60)\}. Il join dà tre tuple, con Mori due volte perché ha due impiegati; la proiezione ne lascia una. Il join serve a restringere ai soli dirigenti, quindi non serve alcuna rinomina.
  6. Impiegati che guadagnano più del loro dirigente. Servono due copie di Employee, quindi self-join con ρ\rho e theta-join: πBadge,Surname,Salary,M.Bdg,M.Srn,M.Slry(Manage⋈Employee=BadgeEmployee ⋈M.Bdg=Manager ∧ Salary>M.SlryρM.Bdg,M.Srn,M.Age,M.Slry←Badge,Surname,Age,Salary(Employee))\pi_{\text{Badge},\text{Surname},\text{Salary},\text{M.Bdg},\text{M.Srn},\text{M.Slry}}\Big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\text{Employee}\ \bowtie_{\text{M.Bdg}=\text{Manager}\ \wedge\ \text{Salary}>\text{M.Slry}}\rho_{\text{M.Bdg},\text{M.Srn},\text{M.Age},\text{M.Slry}\leftarrow\text{Badge},\text{Surname},\text{Age},\text{Salary}}(\text{Employee})\Big) Il primo join dà 5 tuple, il secondo tiene le coppie con stipendio maggiore. Unico risultato: (7309, Rossi, 45, 5698, Bruni, 42).
  7. Dirigenti i cui impiegati guadagnano tutti più di 42. Si usa il complemento, perché l'algebra non ha il ∀\forall: tutti i dirigenti meno quelli con un impiegato ≤42\le42. πManager(Manage)−πManager(Manage⋈Employee=BadgeσSalary≤42(Employee))={8123}\pi_{\text{Manager}}(\text{Manage})-\pi_{\text{Manager}}\big(\text{Manage}\bowtie_{\text{Employee}=\text{Badge}}\sigma_{\text{Salary}\le42}(\text{Employee})\big)=\{8123\} Il sottraendo è {5698,4076}\{5698,4076\}: Bianchi (38) e Neri (35) sono sotto soglia. Lupi dirige solo Mori (50).
    • SQL con EXCEPT: SELECT DISTINCT Manager FROM Manage EXCEPT SELECT m.Manager FROM Manage m JOIN Employee e ON m.Employee = e.Badge WHERE e.Salary <= 42;
  8. Dirigenti che hanno a loro volta un dirigente: un badge che compare sia come Manager sia come Employee. ρWithMgr←Manager(πManager(Manage))∩ρWithMgr←Employee(πEmployee(Manage))={5698,4076}\rho_{\text{WithMgr}\leftarrow\text{Manager}}\big(\pi_{\text{Manager}}(\text{Manage})\big)\cap\rho_{\text{WithMgr}\leftarrow\text{Employee}}\big(\pi_{\text{Employee}}(\text{Manage})\big)=\{5698,4076\} Equivale al self-join con rinomina di entrambe le colonne della copia.
    • Errore: σManager=Employee(Manage)\sigma_{\text{Manager}=\text{Employee}}(\text{Manage}) è vuota, perché confronta due attributi della stessa tupla.

Altri esercizi sullo stesso schema

    1. Impiegati senza dirigente: πBadge(Employee)−ρ(πEmployee(Manage))={8123}\pi_{\text{Badge}}(\text{Employee})-\rho(\pi_{\text{Employee}}(\text{Manage}))=\{8123\}.
    1. Dirigenti con almeno due impiegati: self-join con Employee≠E2\text{Employee}\neq\text{E2}, risultato {5698,4076}\{5698,4076\}.
    1. Stipendio medio per dirigente: (4076;38,5)(4076;38{,}5), (5698;41,5)(5698;41{,}5), (8123;50)(8123;50).

Errori tipici

  • Rinominare una sola colonna nel self-join.
  • Selezionare dopo aver proiettato via l'attributo.
  • Dimenticare che il join perde le tuple dangling.

Teoria collegata