Salta al contenuto
Note per Studenti Algebra relazionale - operatori di base e join

Algebra relazionale - operatori di base e join

In questa pagina 11

Prerequisiti: Modello relazionale - relazioni, chiavi e vincoliIl modello relazionale (Codd, IBM, 1970) rappresenta i dati con relazioni, cioè tabelle, ed è basato su valori: i legami tra relazioni sono confronti di valori, non puntatori, il che garantisce indipendenza dalle strutture fisiche, portabilità e bidirezionalità. Una relazione matematica è un sottoinsieme del prodotto cartesiano di n domini (insieme di n-uple ordinate, senza duplicati né ordine tra le righe); una relazione del modello è un insieme di tuple, funzioni dagli attributi ai valori del dominio, quindi non posizionale. Si distinguono schema di relazione e istanza, schema di base di dati (relazioni più vincoli) e istanza. NULL è un valore speciale fuori da ogni dominio. I vincoli di integrità sono intra-relazionali (di dominio, di tupla, di chiave) e inter-relazionali (integrità referenziale, con la chiave esterna). Superchiave: insieme di attributi che non ripete mai i valori; chiave: superchiave minimale; ogni relazione ne ha almeno una (tutti gli attributi); la chiave primaria è una chiave scelta, senza NULL.Modello relazionale - relazioni, chiavi e vincoli → (relazione come insieme di tuple, chiavi, chiavi esterne) e Operazioni tra insiemiUnione, intersezione, differenza, complementare e prodotto cartesiano, con le leggi di De Morgan e il legame con la logica.Operazioni tra insiemi → (unione, intersezione, differenza e prodotto cartesiano di insiemi). Si prosegue con 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 → e con 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 →, che è la sua implementazione "reale". Gli esercizi svolti sono in Esercizio - Algebra relazionale su impiegati e dirigenti (esercizi di algebra relazionale del corso).

Operazioni sul modello relazionale

Dati uno schema e un'istanza del database, le operazioni si dividono in due famiglie:

  • un aggiornamento è una funzione che porta l'istanza in una nuova istanza valida, cioè che rispetta tutti i vincoli di integrità;
  • una interrogazione (query) è una funzione che porta l'istanza in una relazione (il risultato); il database non cambia.

Aggiornamenti e vincoli

Operazione Vincoli che può violare Alternative
Inserimento dominio, tupla, chiave, integrità referenziale rifiutare l'inserimento; oppure correggere la causa della violazione
Modifica dominio, tupla, chiave, integrità referenziale rifiutare (restrict); oppure propagare (cascade)
Cancellazione integrità referenziale rifiutare (restrict); propagare (cascade); mettere a NULL (set null) o a un valore di default (set default) gli attributi che puntano

Esempio. Dipendente(matricola, cognome, reparto) con reparto chiave esterna verso Reparto(codice, nome). Se si cancella il reparto D e tre dipendenti hanno reparto = 'D': con restrict la cancellazione è rifiutata; con cascade spariscono anche i tre dipendenti; con set null i tre restano con reparto = NULL; con set default passano al reparto di default (che deve esistere).

Set null è impossibile se l'attributo che punta fa parte della chiave primaria, perché una chiave primaria non può contenere NULL. In SQL queste scelte si dichiarano con ON DELETE e ON UPDATE, vedi SQL - definizione dei dati e vincoliSQL (standard ISO 9075) è un linguaggio dichiarativo con una parte di definizione dei dati (DDL: CREATE/DROP/ALTER di database, schemi, tipi enumerati, domini, tabelle) e una di manipolazione (DML: INSERT, DELETE, UPDATE, SELECT). Una tabella SQL è un multi-insieme di righe (può avere duplicati), quindi non è una relazione in senso stretto. CREATE TABLE elenca colonne con tipo e vincoli: NOT NULL, DEFAULT, CHECK (di colonna o di tupla), PRIMARY KEY (una sola, anche composta), UNIQUE, FOREIGN KEY ... REFERENCES con ON DELETE/ON UPDATE (NO ACTION, CASCADE, SET NULL, SET DEFAULT). I tipi principali sono CHAR/VARCHAR, NUMERIC, INTEGER, SERIAL, BOOLEAN, DATE, TIME, TIMESTAMP, più UUID, intervalli e JSON in PostgreSQL. DROP ... CASCADE cancella anche gli oggetti dipendenti, RESTRICT (predefinito) rifiuta se ce ne sono. DELETE e UPDATE senza WHERE agiscono su tutta la tabella.SQL - definizione dei dati e vincoli →.

L'algebra relazionale

L'algebra relazionale è un linguaggio procedurale: un'interrogazione dice come costruire il risultato, con una sequenza di operatori. Ogni operatore ha come operandi una o due relazioni e produce una relazione, quindi gli operatori si compongono in espressioni. (SQL invece è dichiarativo: dice che cosa si vuole.)

Poiché una relazione è un insieme, i duplicati non esistono: ogni risultato è privo di tuple ripetute. È la differenza principale rispetto a SQL, dove una tabella è un multi-insieme.

Operatori
Primitivi unione ∪\cup, differenza −-, prodotto ×\times, rinomina ρ\rho, selezione σ\sigma, proiezione π\pi
Derivati intersezione ∩\cap, join naturale ⋈\bowtie, theta-join ⋈φ\bowtie_\varphi, outer join
Insiemistici ∪\cup, −-, ×\times, ∩\cap
Relazionali ρ\rho, σ\sigma, π\pi, join, outer join

"Derivato" significa esprimibile con i primitivi, per esempio R∩S=R−(R−S)R\cap S=R-(R-S) e R⋈φS=σφ(R×S)R\bowtie_\varphi S=\sigma_\varphi(R\times S).

Operatori insiemistici

Definizione (compatibilità all'unione). Due relazioni sono compatibili all'unione se hanno lo stesso numero di attributi e ogni coppia di attributi ha stesso nome e stesso dominio.

Intersezione, unione e differenza richiedono relazioni compatibili all'unione. Dati

Graduated: Badge Surname Age
7274 Rossi 42
7432 Neri 54
9824 Verdi 45
Manager: Badge Surname Age
9297 Neri 33
7432 Neri 54
9824 Verdi 45

i tre operatori danno (sempre senza duplicati):

  • Graduated∩Manager={t∣t∈Graduated∧t∈Manager}={(7432,Neri,54),(9824,Verdi,45)}\text{Graduated}\cap\text{Manager}=\{t\mid t\in\text{Graduated}\wedge t\in\text{Manager}\}=\{(7432,\text{Neri},54),(9824,\text{Verdi},45)\};
  • Graduated∪Manager\text{Graduated}\cup\text{Manager}: le quattro tuple distinte (7274,Rossi,42)(7274,\text{Rossi},42), (7432,Neri,54)(7432,\text{Neri},54), (9297,Neri,33)(9297,\text{Neri},33), (9824,Verdi,45)(9824,\text{Verdi},45) (le due tuple comuni compaiono una volta sola);
  • Graduated−Manager={(7274,Rossi,42)}\text{Graduated}-\text{Manager}=\{(7274,\text{Rossi},42)\}: i laureati che non sono dirigenti. La differenza non è commutativa.

Definizione (prodotto). Date R1(X1,…,Xn)R_1(X_1,\dots,X_n) e R2(Y1,…,Ym)R_2(Y_1,\dots,Y_m), il prodotto R1×R2R_1\times R_2 ha schema (X1,…,Xn,Y1,…,Ym)(X_1,\dots,X_n,Y_1,\dots,Y_m), grado n+mn+m e cardinalità ∣R1∣⋅∣R2∣|R_1|\cdot|R_2|: ogni tupla del primo operando è concatenata a ogni tupla del secondo.

Il nome "prodotto cartesiano" è un po' improprio: il risultato non è l'insieme di coppie di tuple, ma di tuple "incollate". Con Graduated×Manager\text{Graduated}\times\text{Manager} si hanno 3⋅3=93\cdot3=9 tuple di 6 attributi; poiché i due schemi hanno gli stessi nomi, per scrivere il prodotto bisogna prima rinominare (altrimenti ci sarebbero due attributi Badge).

Rinomina

Definizione (rinomina). ρA1,…,Ak←B1,…,Bk(R)\rho_{A_1,\dots,A_k\leftarrow B_1,\dots,B_k}(R) cambia i nomi degli attributi BiB_i in AiA_i. Si modifica lo schema, non l'istanza: domini e valori restano.

Serve a due scopi: rendere compatibili all'unione due relazioni e distinguere gli attributi omonimi in un prodotto o in un join.

Esempio (compatibilità). Paternity(Father, Child) e Maternity(Mother, Child) non sono compatibili (Father ≠ Mother). Per ottenere tutti i genitori: ρParent←Father(Paternity) ∪ ρParent←Mother(Maternity)\rho_{\text{Parent}\leftarrow\text{Father}}(\text{Paternity})\ \cup\ \rho_{\text{Parent}\leftarrow\text{Mother}}(\text{Maternity}) con schema (Parent,Child)(\text{Parent},\text{Child}) e le sei tuple dei due operandi, per esempio (Adamo,Abele)(\text{Adamo},\text{Abele}) e (Eva,Abele)(\text{Eva},\text{Abele}).

Esempio (più attributi). ρSite,Pay←Office,Salary(Clerk)∪ρSite,Pay←Factory,Wages(Worker)\rho_{\text{Site},\text{Pay}\leftarrow\text{Office},\text{Salary}}(\text{Clerk})\cup\rho_{\text{Site},\text{Pay}\leftarrow\text{Factory},\text{Wages}}(\text{Worker}) unisce Clerk(Surname, Office, Salary) e Worker(Surname, Factory, Wages) nello schema (Surname,Site,Pay)(\text{Surname},\text{Site},\text{Pay}).

Selezione

Definizione (selezione). σφ(R)\sigma_\varphi(R) ha lo stesso schema di RR e contiene il sottoinsieme delle tuple di RR che soddisfano la proposizione φ\varphi. La proposizione è:

  • Ai θ AjA_i\ \theta\ A_j, con Ai,AjA_i,A_j attributi di RR sullo stesso dominio;
  • Ai θ cA_i\ \theta\ c, con cc costante;
  • dove θ∈{<,>,=,≠,≤,≥}\theta\in\{<,>,=,\neq,\leq,\geq\};
  • combinazione di proposizioni con ∧\wedge, ∨\vee, ¬\neg.

Dati Employee(Badge, Surname, Branch, Salary) con (7309,Rossi,Roma,55)(7309,\text{Rossi},\text{Roma},55), (5998,Neri,Milano,64)(5998,\text{Neri},\text{Milano},64), (9553,Milano,Milano,44)(9553,\text{Milano},\text{Milano},44), (5698,Rossi,Roma,64)(5698,\text{Rossi},\text{Roma},64):

  • stipendio maggiore di 50: σSalary>50(Employee)\sigma_{\text{Salary}>50}(\text{Employee}) restituisce tre tuple (tutte tranne la terza);
  • stipendio maggiore di 50 e filiale Milano: σSalary>50 ∧ Branch=Milano(Employee)\sigma_{\text{Salary}>50\ \wedge\ \text{Branch}=\text{Milano}}(\text{Employee}) restituisce solo (5998,Neri,Milano,64)(5998,\text{Neri},\text{Milano},64);
  • cognome uguale alla filiale (confronto tra due attributi): σSurname=Branch(Employee)\sigma_{\text{Surname}=\text{Branch}}(\text{Employee}) restituisce (9553,Milano,Milano,44)(9553,\text{Milano},\text{Milano},44).

Proiezione

Definizione (proiezione). πA1,…,Ak(R)\pi_{A_1,\dots,A_k}(R) ha come schema un sottoinsieme degli attributi di RR e contiene le tuple di RR ristrette a quegli attributi. Il grado è kk; la cardinalità è ≤∣R∣\le|R|: è minore se, dopo aver tolto colonne, alcune tuple diventano uguali e (essendo RR un insieme) i duplicati spariscono; è uguale a ∣R∣|R| se gli attributi proiettati contengono una superchiave.

Con lo stesso Employee, πBadge,Surname(Employee)\pi_{\text{Badge},\text{Surname}}(\text{Employee}) ha quattro tuple, mentre πSurname,Branch(Employee)\pi_{\text{Surname},\text{Branch}}(\text{Employee}) ne ha tre: (Rossi,Roma)(\text{Rossi},\text{Roma}) compare una volta sola.

Selezione e proiezione insieme

Sono operatori ortogonali: la selezione fa una decomposizione orizzontale (sceglie righe), la proiezione una verticale (sceglie colonne).

"Badge e cognome dei dipendenti con stipendio maggiore di 50" si scrive πBadge,Surname(σSalary>50(Employee))\pi_{\text{Badge},\text{Surname}}(\sigma_{\text{Salary}>50}(\text{Employee})): si valuta dall'interno all'esterno. Scambiare l'ordine, σSalary>50(πBadge,Surname(Employee))\sigma_{\text{Salary}>50}(\pi_{\text{Badge},\text{Surname}}(\text{Employee})), è sbagliato: dopo la proiezione l'attributo Salary non esiste più e la selezione non è definita. In generale σ\sigma e π\pi non commutano; commutano solo quando gli attributi usati dalla selezione sono un sottoinsieme di quelli della proiezione.

Join

Il prodotto da solo produce quasi sempre tuple prive di senso (si accoppia ogni dipendente con ogni reparto). Il join accoppia solo le tuple "giuste".

Definizione (theta-join). Date R1(X)R_1(X) e R2(Y)R_2(Y) senza attributi omonimi e una proposizione φ\varphi che confronta attributi di R1R_1 con attributi di R2R_2 (e costanti), R1⋈φR2=σφ(R1×R2).R_1\bowtie_\varphi R_2=\sigma_\varphi(R_1\times R_2). Grado n+mn+m; cardinalità 0≤∣R1⋈φR2∣≤∣R1∣⋅∣R2∣0\le|R_1\bowtie_\varphi R_2|\le|R_1|\cdot|R_2| (detta anche selettività).

Se φ\varphi è una congiunzione di uguaglianze Ai=BjA_i=B_j si parla di equi-join.

Esempio (equi-join). Con Employee(Surname, Dep) = {(Rossi,A),(Neri,B),(Bianchi,B)}\{(\text{Rossi},A),(\text{Neri},B),(\text{Bianchi},B)\} e Department(Code, Manager) = {(A,Mori),(B,Bruni)}\{(A,\text{Mori}),(B,\text{Bruni})\}, Employee⋈Dep=CodeDepartment\text{Employee}\bowtie_{\text{Dep}=\text{Code}}\text{Department} dà (Rossi,A,A,Mori)(\text{Rossi},A,A,\text{Mori}), (Neri,B,B,Bruni)(\text{Neri},B,B,\text{Bruni}), (Bianchi,B,B,Bruni)(\text{Bianchi},B,B,\text{Bruni}): l'attributo di join compare due volte, con nomi diversi.

Definizione (join naturale). Siano R1(X,W)R_1(X,W) e R2(Y,Z)R_2(Y,Z) con W=(W1,…,Wm)W=(W_1,\dots,W_m) e Z=(Z1,…,Zm)Z=(Z_1,\dots,Z_m) gli attributi con lo stesso nome. Allora R1⋈R2=πX,W1,…,Wm,Y(R1⋈W1=Z1∧⋯∧Wm=ZmR2).R_1\bowtie R_2=\pi_{X,W_1,\dots,W_m,Y}\big(R_1\bowtie_{W_1=Z_1\wedge\dots\wedge W_m=Z_m}R_2\big).

È un equi-join sugli attributi omonimi, seguito da una proiezione che tiene una sola copia di ogni attributo comune. Con Department(Dep, Manager) (stesso nome Dep in entrambe) Employee⋈Department\text{Employee}\bowtie\text{Department} dà (Rossi,A,Mori)(\text{Rossi},A,\text{Mori}), (Neri,B,Bruni)(\text{Neri},B,\text{Bruni}), (Bianchi,B,Bruni)(\text{Bianchi},B,\text{Bruni}).

Il join naturale è comodo ma fragile: se due relazioni hanno per caso un attributo omonimo che non va usato per il join (per esempio due Nome), il risultato cambia in silenzio. Nei temi d'esame conviene scrivere il join con la condizione esplicita (equi-join) e rinominare dove serve.

Cardinalità del join

Siano R1(X)R_1(X), R2(Y)R_2(Y) e Z=X∩YZ=X\cap Y gli attributi su cui si fa il join naturale (o l'equi-join).

Situazione Cardinalità
caso generale 0≤∣R1⋈R2∣≤∣R1∣⋅∣R2∣0\le\lvert R_1\bowtie R_2\rvert\le\lvert R_1\rvert\cdot\lvert R_2\rvert
ZZ è chiave di R2R_2 0≤∣R1⋈R2∣≤∣R1∣0\le\lvert R_1\bowtie R_2\rvert\le\lvert R_1\rvert
ZZ è chiave di R2R_2 e chiave esterna di R1R_1 verso R2R_2, con vincolo di integrità referenziale ∣R1⋈R2∣=∣R1∣\lvert R_1\bowtie R_2\rvert=\lvert R_1\rvert

Esempio. Employee: (Rossi,A),(Neri,B),(Bianchi,B),(Neri,C)(\text{Rossi},A),(\text{Neri},B),(\text{Bianchi},B),(\text{Neri},C) (4 tuple).

  • Department = (A,Mori),(B,Bruni),(B,Verdi)(A,\text{Mori}),(B,\text{Bruni}),(B,\text{Verdi}): Dep non è chiave, risultano 5 tuple (su un massimo di 4⋅3=124\cdot3=12): Neri\text{Neri} e Bianchi\text{Bianchi} si accoppiano con entrambi i dirigenti di BB, Neri,C\text{Neri},C non si accoppia.
  • Department = (A,Mori),(B,Bruni),(D,Verdi)(A,\text{Mori}),(B,\text{Bruni}),(D,\text{Verdi}): Dep è chiave ma non chiave esterna di Employee (c'è CC senza reparto): 3 tuple, meno delle 4 di Employee.
  • Con (Neri,D)(\text{Neri},D) al posto di (Neri,C)(\text{Neri},C) e lo stesso Department: Dep è chiave di Department e chiave esterna di Employee: 4 tuple =∣Employee∣=|\text{Employee}|.

Tuple dangling

Una tupla che non trova corrispondente nell'altro operando non contribuisce al risultato: si dice dangling (pendente). Nell'esempio, (Neri,C)(\text{Neri},C) di Employee e (D,Verdi)(D,\text{Verdi}) di Department scompaiono dal join. Per mantenerle, con valori NULL, servono gli outer 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 →).

Join di una relazione con se stessa

Per accoppiare tuple della stessa relazione si usa la rinomina. Con Employee(Badge, Surname, Age, Salary) e Manage(Employee, Manager) (tutti gli attributi sono badge), "i dipendenti che guadagnano più del loro dirigente" richiede due copie di Employee: una per il dipendente, una rinominata per il dirigente.

π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 passaggio con theta-join evita una selezione dopo un equi-join. Il risultato completo è nell'esercizio Esercizio - Algebra relazionale su impiegati e dirigenti (esercizi di algebra relazionale del corso).

Valori NULL

La selezione valuta ogni condizione atomica separatamente, e un confronto con NULL non è vero (il risultato è "sconosciuto"). 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(Employee)\sigma_{\text{Age}>40}(\text{Employee}) restituisce solo Bianchi;
  • σAge≤40(Employee)\sigma_{\text{Age}\le40}(\text{Employee}) restituisce solo Rossi;
  • quindi σAge>40∪σAge≤40≠Employee\sigma_{\text{Age}>40}\cup\sigma_{\text{Age}\le40}\neq\text{Employee}: Neri sparisce da entrambe. Lo stesso vale per σAge>40 ∨ Age≤40\sigma_{\text{Age}>40\ \vee\ \text{Age}\le40}.

Per gestire i NULL si introducono le condizioni specifiche A IS NULLA\ \text{IS NULL} e A IS NOT NULLA\ \text{IS NOT NULL}:

σAge>40 ∨ Age≤40 ∨ Age IS NULL(Employee)=Employee.\sigma_{\text{Age}>40\ \vee\ \text{Age}\le40\ \vee\ \text{Age IS NULL}}(\text{Employee})=\text{Employee}.

Con la logica a tre valori (vero, falso, sconosciuto) ∧\wedge, ∨\vee, ¬\neg si comportano così, e la selezione tiene solo le tuple per cui la condizione è vera:

aa bb a∧ba\wedge b a∨ba\vee b ¬a\neg a
V sconosciuto sconosciuto V F
F sconosciuto F sconosciuto V
sconosciuto sconosciuto sconosciuto sconosciuto sconosciuto

Anche nei join gli attributi NULL non si accoppiano mai: NULL=NULL\text{NULL}=\text{NULL} non è vero.

Come si scrive una query

  1. Individuare le relazioni coinvolte e gli attributi che servono nel risultato.
  2. Collegarle con join (sui legami chiave-chiave esterna), rinominando gli attributi omonimi o le copie della stessa relazione.
  3. Filtrare con σ\sigma (meglio il prima possibile, sulle relazioni piccole, prima dei join: il risultato è lo stesso ma l'espressione è più efficiente).
  4. Proiettare con π\pi solo gli attributi richiesti (e solo alla fine, se la selezione usa attributi che non si vedono nel risultato).
  5. Assegnare nomi alle relazioni intermedie (R1←…R_1\leftarrow\dots) per leggibilità; le espressioni si leggono dall'interno all'esterno e da sinistra a destra.
  6. Controllare su due o tre tuple a mano, con attenzione ai duplicati, ai NULL e ai casi limite ("nessuno", "tutti", "almeno due").

Per i casi con "massimo", "tutti", "per ciascuno" servono l'aggregazione e la divisione, vedi 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 →. Con i soli operatori di questa nota si possono già esprimere i "per tutti" con la differenza: "i dirigenti i cui dipendenti guadagnano tutti più di 42" =π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), cioè tutti i dirigenti meno quelli che hanno almeno un dipendente sotto soglia. È il metodo del complemento: "tutti" = "non esiste nessuno che non".

Errori tipici

  • Scrivere σManager=Employee(Manage)\sigma_{\text{Manager}=\text{Employee}}(\text{Manage}) per "dirigenti che hanno a loro volta un dirigente": confronta due attributi della stessa tupla, quindi trova chi dirige se stesso (nessuno). Serve un join della relazione con una sua copia rinominata.
  • Fare la proiezione prima della selezione quando la selezione usa attributi eliminati.
  • Usare un join naturale tra relazioni con attributi omonimi che non c'entrano.
  • Dimenticare la rinomina nelle unioni (relazioni non compatibili) e nei join con se stessi.
  • Ignorare i NULL: σA>c∪σA≤c≠R\sigma_{A>c}\cup\sigma_{A\le c}\neq R.
  • Dare per scontato che il risultato contenga duplicati: in algebra non ce ne sono.

Domande d'esame

1. Quando due relazioni sono compatibili all'unione e perché la rinomina serve prima di un'unione? Traccia. Stesso numero di attributi con stessi nomi e domini. Se i nomi sono diversi (Father/Mother) l'unione non è definita: si rinominano gli attributi con ρ\rho cambiando solo lo schema, poi si fa ∪\cup.

2. Perché πBadge,Surname(σSalary>50(E))\pi_{\text{Badge},\text{Surname}}(\sigma_{\text{Salary}>50}(E)) non si può riscrivere come σSalary>50(πBadge,Surname(E))\sigma_{\text{Salary}>50}(\pi_{\text{Badge},\text{Surname}}(E))? Traccia. La proiezione elimina Salary, quindi la selezione che segue usa un attributo inesistente. Selezione e proiezione commutano solo se gli attributi della selezione sono tra quelli proiettati.

3. Quante tuple ha R1⋈R2R_1\bowtie R_2 se l'attributo di join è chiave di R2R_2 e chiave esterna di R1R_1? Traccia. Esattamente ∣R1∣|R_1|: ogni tupla di R1R_1 ha una sola tupla corrispondente in R2R_2 (esiste per l'integrità referenziale ed è unica perché è una chiave).

4. Cosa restituisce σA>40(R)∪σA≤40(R)\sigma_{A>40}(R)\cup\sigma_{A\le40}(R) se AA ha valori NULL? Traccia. Non tutta RR: un confronto con NULL non è vero, quindi le tuple con AA nullo mancano in entrambe. Servono A IS NULLA\ \text{IS NULL} / A IS NOT NULLA\ \text{IS NOT NULL}.

Versione ripasso

Operazioni: un aggiornamento porta l'istanza in una nuova istanza valida; un'interrogazione porta l'istanza in una relazione. Cancellazione con integrità referenziale: restrict, cascade, set null (non su chiave primaria), set default. In SQL: ON DELETE e ON UPDATE (SQL - definizione dei dati e vincoliSQL (standard ISO 9075) è un linguaggio dichiarativo con una parte di definizione dei dati (DDL: CREATE/DROP/ALTER di database, schemi, tipi enumerati, domini, tabelle) e una di manipolazione (DML: INSERT, DELETE, UPDATE, SELECT). Una tabella SQL è un multi-insieme di righe (può avere duplicati), quindi non è una relazione in senso stretto. CREATE TABLE elenca colonne con tipo e vincoli: NOT NULL, DEFAULT, CHECK (di colonna o di tupla), PRIMARY KEY (una sola, anche composta), UNIQUE, FOREIGN KEY ... REFERENCES con ON DELETE/ON UPDATE (NO ACTION, CASCADE, SET NULL, SET DEFAULT). I tipi principali sono CHAR/VARCHAR, NUMERIC, INTEGER, SERIAL, BOOLEAN, DATE, TIME, TIMESTAMP, più UUID, intervalli e JSON in PostgreSQL. DROP ... CASCADE cancella anche gli oggetti dipendenti, RESTRICT (predefinito) rifiuta se ce ne sono. DELETE e UPDATE senza WHERE agiscono su tutta la tabella.SQL - definizione dei dati e vincoli →).

Algebra: linguaggio procedurale, gli operatori si compongono. Una relazione è un insieme: niente duplicati. Primitivi: ∪\cup, −-, ×\times, ρ\rho, σ\sigma, π\pi. Derivati: ∩\cap, ⋈\bowtie, ⋈φ\bowtie_\varphi, outer join. Esempi: R∩S=R−(R−S)R\cap S=R-(R-S) e R⋈φS=σφ(R×S)R\bowtie_\varphi S=\sigma_\varphi(R\times S).

Compatibilità all'unione: stesso numero di attributi, stessi nomi e stessi domini; serve per ∪\cup, ∩\cap, −-. Con Graduated e Manager (tre tuple ciascuna): ∩\cap dà (7432,Neri,54) e (9824,Verdi,45); ∪\cup dà quattro tuple distinte; −- dà solo (7274,Rossi,42). La differenza non è commutativa.

Prodotto: grado n+mn+m, cardinalità ∣R1∣⋅∣R2∣|R_1|\cdot|R_2|; con attributi omonimi serve prima la rinomina. Con 3 tuple per 3 tuple si ottengono 3⋅3=93\cdot3=9 tuple.

Rinomina ρA←B(R)\rho_{A\leftarrow B}(R): cambia lo schema, non l'istanza. Esempio: ρParent←Father(Paternity)∪ρParent←Mother(Maternity)\rho_{\text{Parent}\leftarrow\text{Father}}(\text{Paternity})\cup\rho_{\text{Parent}\leftarrow\text{Mother}}(\text{Maternity}).

Selezione σφ(R)\sigma_\varphi(R): stesso schema, sottoinsieme delle tuple che soddisfano φ\varphi. Confronti A θ A′A\ \theta\ A' o A θ cA\ \theta\ c, combinati con ∧\wedge, ∨\vee, ¬\neg. Con Employee: σSalary>50\sigma_{\text{Salary}>50} dà tre tuple; σSalary>50 ∧ Branch=Milano\sigma_{\text{Salary}>50\ \wedge\ \text{Branch}=\text{Milano}} dà solo (5998,Neri,Milano,64); σSurname=Branch\sigma_{\text{Surname}=\text{Branch}} dà (9553,Milano,Milano,44).

Proiezione πX(R)\pi_X(R): al più ∣R∣|R| tuple, i duplicati spariscono. È uguale a ∣R∣|R| se XX contiene una superchiave. Con Employee, πSurname,Branch\pi_{\text{Surname},\text{Branch}} dà tre tuple perché (Rossi,Roma) compare una volta sola.

Selezione e proiezione: la selezione è una decomposizione orizzontale (righe), la proiezione una verticale (colonne). πBadge,Surname(σSalary>50(Employee))\pi_{\text{Badge},\text{Surname}}(\sigma_{\text{Salary}>50}(\text{Employee})) si valuta dall'interno; scambiare le due è sbagliato, perché Salary sparisce con la proiezione. Commutano solo se gli attributi della selezione sono nella proiezione.

Theta-join ed equi-join: R1⋈φR2=σφ(R1×R2)R_1\bowtie_\varphi R_2=\sigma_\varphi(R_1\times R_2), con 0≤∣⋅∣≤∣R1∣∣R2∣0\le|\cdot|\le|R_1||R_2|. Se φ\varphi è una congiunzione di uguaglianze è un equi-join. Esempio: Employee(Surname, Dep) con Department(Code, Manager) su Dep=Code\text{Dep}=\text{Code} dà tre tuple, con l'attributo di join due volte.

Join naturale: equi-join sugli attributi omonimi, poi proiezione che tiene una copia sola. È fragile: due omonimi che non c'entrano cambiano il risultato in silenzio. Negli esami conviene l'equi-join esplicito.

Cardinalità del join:

  • caso generale: 0≤∣R1⋈R2∣≤∣R1∣⋅∣R2∣0\le|R_1\bowtie R_2|\le|R_1|\cdot|R_2|;
  • ZZ chiave di R2R_2: ∣R1⋈R2∣≤∣R1∣|R_1\bowtie R_2|\le|R_1|;
  • ZZ chiave di R2R_2 e chiave esterna di R1R_1, con integrità referenziale: ∣R1⋈R2∣=∣R1∣|R_1\bowtie R_2|=|R_1|.

Con Employee di quattro tuple, il join con Department dà 5, 3 o 4 tuple a seconda che Dep sia o no chiave e chiave esterna.

Tuple dangling: le tuple senza corrispondenza escono dal join; gli outer join le mantengono (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 →).

Self-join: si rinomina una copia della relazione. Per "dipendenti che guadagnano più del loro dirigente":

π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)

Valori NULL: un confronto con NULL non è vero. Se Neri ha Age = NULL, σAge>40∪σAge≤40≠Employee\sigma_{\text{Age}>40}\cup\sigma_{\text{Age}\le40}\neq\text{Employee}. Soluzione: aggiungere Age IS NULL\text{Age IS NULL} alla condizione. Logica a tre valori: V∨sconosciuto=V\text{V}\vee\text{sconosciuto}=\text{V}, F∧sconosciuto=F\text{F}\wedge\text{sconosciuto}=\text{F}; la selezione tiene solo le tuple vere. Nei join i NULL non si accoppiano.

Il "tutti": i dirigenti i cui dipendenti guadagnano tutti più di 42 sono tutti i dirigenti meno quelli con almeno un dipendente sotto soglia:

π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)

Errori tipici:

  • σManager=Employee(Manage)\sigma_{\text{Manager}=\text{Employee}}(\text{Manage}) per "chi ha a sua volta un dirigente": confronta due attributi della stessa tupla, serve un self-join;
  • proiettare prima di selezionare su un attributo eliminato;
  • join naturale su omonimi che non c'entrano, o rinomina dimenticata nelle unioni;
  • ignorare i NULL, aspettarsi duplicati.

Prerequisiti: Modello relazionale - relazioni, chiavi e vincoliIl modello relazionale (Codd, IBM, 1970) rappresenta i dati con relazioni, cioè tabelle, ed è basato su valori: i legami tra relazioni sono confronti di valori, non puntatori, il che garantisce indipendenza dalle strutture fisiche, portabilità e bidirezionalità. Una relazione matematica è un sottoinsieme del prodotto cartesiano di n domini (insieme di n-uple ordinate, senza duplicati né ordine tra le righe); una relazione del modello è un insieme di tuple, funzioni dagli attributi ai valori del dominio, quindi non posizionale. Si distinguono schema di relazione e istanza, schema di base di dati (relazioni più vincoli) e istanza. NULL è un valore speciale fuori da ogni dominio. I vincoli di integrità sono intra-relazionali (di dominio, di tupla, di chiave) e inter-relazionali (integrità referenziale, con la chiave esterna). Superchiave: insieme di attributi che non ripete mai i valori; chiave: superchiave minimale; ogni relazione ne ha almeno una (tutti gli attributi); la chiave primaria è una chiave scelta, senza NULL.Modello relazionale - relazioni, chiavi e vincoli →, Operazioni tra insiemiUnione, intersezione, differenza, complementare e prodotto cartesiano, con le leggi di De Morgan e il legame con la logica.Operazioni tra insiemi →. Esercizi: Esercizio - Algebra relazionale su impiegati e dirigenti (esercizi di algebra relazionale del corso).

Esercizi su questo argomento

Teoria collegata