È un linguaggio di interrogazione costituito da un insieme di operatori definiti su relazioni che producono relazioni.
Le interrogazioni vengono formulate attraverso espressioni algebriche.
Gli operatori sono:
- insiemistici;
- specifici unari;
- specifici tipo join.
## Operatori insiemistici
Le relazioni sono insiemi (di tuple) e per questo possono essere manipolate attraverso operatori mutuati dalla teoria degli insiemi.
A differenza degli insiemi, le relazioni hanno uno schema e, relazioni che hanno lo stesso schema, hanno elementi omogenei.
Le operazioni di unione, sottrazione e intersezione possono essere fatte a parità di schema: ad esempio, si può fare l'unione di un insieme di persone con un altro insieme di persone ma non con un insieme di macchine.
Date due relazioni con gli stessi attributi *R(X)* e *S(X)*, dove *X=\{A1, ..., An\*}, la loro unione, differenza e intersezione è una relazione *T(X)*, che ha gli stessi attributi, e la cui estensione è la seguente:
$
T = R \cup S = \{t | t \in R$ or $t \in S\}
$
$
T = R - S = \{t | t \in R$ and $t \notin S\}
$
$
T = R \cap S = \{t | t \in R$ and $t \in S\}
$
![[operatoriInsiemistici.PNG]]
## Operatori specifici unari
***Selezione:*** $\sigma_F(R) $ è un operatore unario che restituisce una relazione S le cui tuple sono tutte e solo le tuple di R che soddisfano il predicato F. Matematicamente:
$
\sigma_F(R) = \{t \in R | t $ soddisfa $F\}
$
F è un predicato definito sugli attributi di R che utilizza operatori logici e operatori di confronto. Si noti che gli attributi di S coincidono con quelli di R.
**Esempio:** data la relazione *R(A, B, C)*:
$\sigma_{A = a \wedge C = c}(R) $
restituisce una relazione *S(A, B, C)* che ha gli stessi attributi di R e la cui estensione consiste di tutte le tuple di R che soddisfano la condizione A = a $
\wedge
$ C = c.
![[esempioOpSpecificiUnari1.PNG]]
***Proiezione:*** $\pi_Y(R) $ è un operatore unario che, data una relazione con schema *R(X)* e un sottoinsieme di attributi Y di X, restituisce una relazione *S(Y)* le cui tuple si ottengono da quelle di R considerando solo i valori sugli attributi in Y. Matematicamente:
$
\pi_Y(R) = \{t[Y]|t \in R\}
$
**Esempio:** data la proiezione *R(A, B, C)*:
$\pi_{A, B}(R) $
restituisce una relazione *S(A, B)* che ha gli attributi A, B specificati come pedice dell'operatore e la cui estensione consiste di tute e solo le tuple di R proiettate sugli stessi attributi:
![[esempioOpSpecificiUnari2.PNG]]
***Ridenominazione:*** operatore unario che cambia il nome degli attributi di una relazione:
$
\rho_{A1...An \leftarrow B1...Bn}
$
**Esempio:** date le relazioni *Padre(padre, figlio)* e *Madre(madre, figlio)*, generare la relazione *Genitore(genitore, figlio)*:
$ Genitore(genitore, figlio) = \rho_{genitore \leftarrow padre}(Padre) \cup \rho_{genitore \leftarrow madre}(Madre) $
**NOTA:** $ \rho{genitore \leftarrow padre}(Padre) $ modifica lo schema di *Padre* come segue: *Padre(genitore, figlio)*.
## Join
L'operatore join è l'operatore che concente di connettere informazioni contenute in relazioni diverse.
- join naturale
- equi-join
- theta-join
- join esterni
### Join naturale
Correla tuple in relazioni diverse sulla base di valori uguali di attributi con lo stesso nome.
Il join naturale di *R(X) $\bowtie$ S(Y)* produce una relazione *T(Z)* con *Z = X $\cup$ Y* ed estensione *E* definita come segue:
*E = \{t su X $\cup$ t.c. t[X] $\in$ R e t[Y] $\in$ S\*}
dove *t[X]* è la tupla *t* proiettata sugli attributi in X.
**Esempio:** Siano date due relazioni *R(X)* e *S(Y)*, con *X = \{A,B\*} e *Y=\{B,C\*}. Il join naturale produce una relazione *T(Z)*, con *Z = X $\cup$ Y = \{A,B,C\*}, le cui tuple si ottengono concatenando le tuple di *R* e di *S* con lo stesso valore dell’attributo in comune *B*:
![[joinNaturale1.PNG]]
Si noti che se *X $\cap$ Y = $\Phi$*, cioè le due relazioni non hanno attributi in comune, il join naturale degenera nel prodotto cartesiano:
![[joinNaturale2.PNG]]
Si noti che se *X = Y*, cioè le due relazioni hanno gli stessi attributi, il join naturale coincide con l’intersezione:
![[joinNaturale3.PNG]]
### Equi-join
È un operatore che consente di eseguire join anche tra relazioni che non hanno attributi in comune, senza che questo degeneri nel prodotto cartesiano:
$
R \bowtie_F S
$
dove F è un predicato che esprime condizioni di uguaglianza tra attributi delle due relazioni.
Ad esempio, dati R(A,B,C) e S(X,Y,Z), F potrebbe essere:
*F = (A = X and B = Y)*
Il risultato è una relazione che ha gli attributi di *R* e di *S* prendendo una sola volta quelli che appaiono in *F* e come tuple la concatenazione delle tuple di *R* e di *S* che hanno gli stessi valori sugli attributi di join.
**Esempio:**
Prof(codP, nome, età, dip*)
Dip(codD, nomeD, univ, dir*)
Il risultato della seguente espressione:
*Prof $\bowtie_{dip=codD*$ Dip}
è una relazione che ha il seguente schema:
*ProfDip(codP, nome, età, dip, nomeD, univ, dir)*
in cui i due attributi dip e codD sono rappresentati solo da uno di essi.
![[equijoin.PNG]]
L’equi-join (così come il join naturale) è un operatore derivato, nel senso che può essere espresso attraverso altri operatori:
R $\bowtie_F$ S = $\pi_Z$ ($\sigma_F$ (R $\bowtie$ S))
dove $\pi_Z$ produce la proiezione su tutti gli attributi di R e S, prendendo una sola volta quelli che appaiono in F.
## Algebra relazionale per le interrogazioni
Usando gli operatori dell’algebra relazionale è possibile costruire delle espressioni che producono come risultato una relazione.
Tali espressioni possono essere utilizzate per formulare interrogazioni sulle basi di dati relazionali
### Base di dati di esempio
L'esempio di riferimento per le prossime spiegazioni saranno:
![[BDEsempio.PNG]]
Lo schema logico è il seguente:
- **Prodotto**(codP, colore, prezzo, forn*)
- **Fornitore**(codF, nome, città)
- **Composizione**(prod*, comp*)
Gli attributi *prod* e *comp* sono chiavi secondarie definite sul codice dei prodotti.
![[BDDati.PNG]]
## Interrogazioni
- **interrogazioni positive:** si basano su proiezione, selezione, join, unione
- **interrogazioni negative:** serve anche la differenza
### Proiezione-selezione
**Come scoprire i codici dei componenti del prodotto *p1**?*
$\pi_{comp}$ ($\sigma_{prod=p1}$ (Composizione))
Tutta l’informazione è racchiusa nella relazione Composizione, per cui è sufficiente utilizzare operatori unari.
![[proiezioneSelezione.PNG]]
### Proiezione-selezione-join
**Come scoprire il colore dei prodotti di cui è componente il prodotto *p3**?*
$\pi_{colore}$ ($\sigma_{comp = p3}$ (Composizione $\bowtie_{prod = codP}$ Prodotto))
**NOTA:** il join tra *Prodotto* e *Composizione* si basa su una condizione di uguaglianza tra la chiave primaria *codP* e la chiave secondaria *prod*.
![[proiezioneSelezioneJoin1.PNG]]
**Come scoprire i codici e i nomi dei Fornitori di prodotti che hanno il componente p2?**
$\pi_{codF, nome}$ ((Prod $\bowtie_{codP=prod}$ ($\sigma_{comp = p2}$ Comp)) $\bowtie_{forn=codF}$ Forn)
![[proiezioneSelezioneJoin2.PNG]]
**Come scoprire i nomi dei Fornitori dei componenti di prodotti di colore giallo?**
$\pi_{nomeF}$ ($\sigma_{col=giallo}$ Prod $\bowtie_{codP=prod}$ Comp $\bowtie_{comp=codP}$ Prod $\bowtie_{forn=codF}$ Forn)
![[proiezioneSelezioneJoin3.PNG]]
**Come scoprire le coppie di codici di prodotti con lo stesso prezzo?** La relazione coinvolta è Prodotto.
$\pi_{codP, codP'}$ ($\sigma_{codP != codP' AND prezzo = prezzo'}$ (Prodotto $\bowtie$ Prodotto'))
$Prodotto' = \rho_{codP' \leftarrow codP, colore' \leftarrow colore, prezzo' \leftarrow prezzo, forn' \leftarrow forn}Prodotto $
**NOTA:** per fare il prodotto cartesiano di Prodotto con se stesso abbiamo dovuto procedere ad una ridenominazione di Prodotto.
![[proiezioneSelezioneJoin4.PNG]]
### Uso della differenza
**Come scoprire i codici dei prodotti che non hanno componenti?** Le relazioni coinvolte sono Prodotto e Composizione.
$
\pi_{codP}(Prodotto) - \rho_{codP \leftarrow comp}(\pi_{comp}(Composizione))
$
**NOTA:** interrogazione negativa. In AR è necessario usare l’operatore “differenza”.
![[usoDifferenza1.PNG]]
**Come scoprire i codici dei fornitori che NON forniscono il prodotto p1?** Le relazioni coinvolte sono Prodotto e Fornitore.
$
\pi_{codF}(Forn) - \rho_{codF \leftarrow forn}(\pi_{forn}(\sigma_{codP=p1}Prod ))
$
**Come scoprire i codici dei prodotti che NON hanno componenti con un prezzo maggiore di 100?** Per semplicità, suddividiamo il problema in due sotto-problemi:
- calcolo dei codici dei prodotti che hanno qualche componente con un prezzo maggiore di 100;
- calcolo della differenza tra l’insieme dei codici di tutti i prodotti e quello calcolato al passo precedente.
$
R(prod) = \pi_{prod}(Composizione \bowtie_{comp=codP}(\sigma_{prezzo > 100}Prodotto))
\pi_{codP}Prodotto - \rho_{codP \leftarrow prod}R
$
**Come scoprire i codici dei prodotti i cui componenti sono *tutti** di colore giallo?* Le relazioni coinvolte sono Prodotto e Composizione.
La query può essere riformulata come segue: codici dei prodotti che NON hanno alcun componente di colore diverso dal giallo.
$
R(prod) = \pi_{prod}(Composizione \bowtie_{comp=codP}(\sigma_{colore != giallo}Prodotto))
\pi_{codP}Prodotto - \rho_{codP \leftarrow prod}R
$
**Come scoprire i codici dei prodotti che hanno *solo** il componente p3?* La relazione coinvolta è Prodotto.
La query può essere riformulata come segue: codici dei prodotti che hanno il componente p3 e NON hanno alcun altro componente.
$
\pi_{prod}(\sigma_{comp=p3}Comp)) - \pi_{prod}(\sigma_{comp!=p3}Comp))
$
![[usoDifferenza2.PNG]]
**Come scoprire i codici dei componenti di un *unico** prodotto?*
$
\pi_{comp}Comp - \pi_{comp}(\sigma_{comp=comp' AND prof != prod'}(Comp \bowtie Comp'))
Comp' = \rho_{prod' \leftarrow prod, comp' \leftarrow comp}(Comp)
$
La sotto-espressione di destra della prima espressione calcola, attraverso il prodotto cartesiano, i codici dei componenti di almeno due prodotti.
Con la differenza si individuano quindi i codici dei componenti di un unico prodotto.
![[usoDifferenza3.PNG]]