Tuesday, September 11, 2018

Basi di Dati: L'algebra Relazionale

Le basi di dati contengono informazioni che possono essere interrogate, aggiornate e manipolate dalle applicazioni. Per questo motivo sono necessari linguaggi che consentano di selezionare, elaborare e combinare i dati memorizzati nelle tabelle.

L'algebra relazionale è un linguaggio procedurale utilizzato per descrivere interrogazioni sulle basi di dati relazionali. Viene definito procedurale perché, per ottenere un determinato risultato, è necessario specificare la sequenza di operazioni da eseguire.
L'algebra relazionale non è il linguaggio utilizzato direttamente dagli utenti per interrogare un database. Essa rappresenta invece il fondamento teorico su cui si basano molti linguaggi per basi di dati relazionali, tra cui SQL.
Ogni operazione dell'algebra relazionale prende in ingresso una o più relazioni (tabelle) e restituisce sempre una nuova relazione. Questa proprietà, detta chiusura, permette di concatenare più operatori per costruire interrogazioni anche molto complesse.

Gli operatori dell'algebra relazionale possono essere suddivisi in tre gruppi principali:

  • Operatori insiemistici
    • Unione
    • Intersezione
    • Differenza

  • Operatori che selezionano dati da una relazione
    • Selezione (righe)
    • Proiezione (colonne)
  • Operatori che combinano più relazioni
    • Prodotto cartesiano
    • Join

Per poter applicare gli operatori insiemistici, due relazioni devono essere compatibili. Due relazioni R e S sono compatibili quando:

  1. hanno lo stesso numero di attributi (lo stesso grado);
  2. gli attributi corrispondenti appartengono allo stesso dominio.

1. Unione di relazioni

Date due relazioni compatibili R e S, l'unione è la relazione costituita da tutte le tuple appartenenti a R, a S oppure a entrambe. L'operazione di unione è indicata con il simbolo:

R ∪ S

Il risultato dell'operazione contiene tutte le tuple distinte presenti nelle due relazioni.

Supponiamo di avere le seguenti relazioni.

Clienti2000

Codice Nome Cognome Indirizzo
C001 Mario Rossi Via Adige, 30
C003 Luigi Verdi Via Moro, 4
C004 Guido Galli Via Po, 23

Clienti2001

Codice Nome Cognome Indirizzo
C001 Mario Rossi Via Adige, 30
C002 Paolo Bianchi Via Roma, 12
C003 Luigi Verdi Via Moro, 4

Il risultato dell'operazione Clienti2000 ∪ Clienti2001 è la relazione:

Codice Nome Cognome Indirizzo
C001 Mario Rossi Via Adige, 30
C002 Paolo Bianchi Via Roma, 12
C003 Luigi Verdi Via Moro, 4
C004 Guido Galli Via Po, 23

Si osservi che Mario Rossi e Luigi Verdi compaiono una sola volta, nonostante siano presenti in entrambe le relazioni.


Ad esempio, consideriamo l'archivio dell'Anagrafe Tributaria. I contribuenti possono essere suddivisi in due categorie:

  • persone fisiche;
  • persone giuridiche (società, enti e imprese).

Supponiamo di avere le seguenti relazioni:

PersoneFisiche(CodiceFiscale, Nominativo)
PersoneGiuridiche(CodiceFiscale, Denominazione)

Poiché entrambe le relazioni possiedono due attributi compatibili, è possibile eseguirne l'unione per ottenere un unico elenco di contribuenti.


Eliminazione dei duplicati

Una caratteristica importante dell'algebra relazionale è che il risultato di ogni operazione è sempre una relazione, e una relazione, per definizione, non può contenere tuple duplicate. Per questo motivo, durante l'operazione di unione, eventuali tuple duplicate vengono eliminate automaticamente.

Nota: questo comportamento è diverso da quello di SQL. Nel linguaggio SQL, infatti, l'operatore UNION elimina i duplicati, mentre UNION ALL li mantiene.


2. Intersezione di due relazioni

Date due relazioni compatibili R e S, l'intersezione è la relazione costituita da tutte le tuple presenti contemporaneamente in entrambe le relazioni. L'operazione di intersezione è indicata con il simbolo:

R ∩ S

Come per l'unione, l'intersezione può essere eseguita solo tra relazioni compatibili, cioè aventi lo stesso numero di attributi e attributi corrispondenti appartenenti agli stessi domini.

Siano date le seguenti relazioni.

R = Clienti2000

Codice Nome Cognome Indirizzo
C001 Mario Rossi Via Adige, 30
C003 Luigi Verdi Via Moro, 4
C004 Guido Galli Via Po, 23

S = Clienti2001

Codice Nome Cognome Indirizzo
C001 Mario Rossi Via Adige, 30
C002 Paolo Bianchi Via Roma, 12
C003 Luigi Verdi Via Moro, 4

Il risultato dell'operazione R ∩ S è la relazione:

Codice Nome Cognome Indirizzo
C001 Mario Rossi Via Adige, 30
C003 Luigi Verdi Via Moro, 4

Il risultato contiene esclusivamente le tuple presenti sia nella relazione R sia nella relazione S.

Nota: l'intersezione è l'equivalente, per le relazioni, dell'intersezione tra due insiemi studiata in matematica: il risultato contiene soltanto gli elementi comuni ai due insiemi.


3. Differenza di relazioni

Date due relazioni compatibili R e S, la differenza è la relazione costituita da tutte le tuple appartenenti a R ma non a S. L'operazione è indicata con il simbolo:

R − S

Anche la differenza richiede che le due relazioni siano compatibili.

Esempio:

Siano ancora: R = Clienti2000 e S = Clienti2001. Il risultato della differenza: R − S è:

Codice Nome Cognome Indirizzo
C004 Guido Galli Via Po, 23

Infatti il cliente Guido Galli compare nella relazione R, ma non nella relazione S.

È importante osservare che la differenza non è commutativa. In generale: R − S ≠ S − R. Infatti, invertendo l'ordine degli operandi, si ottiene una relazione diversa.


4. Proiezione di una relazione

La proiezione è l'operazione che consente di estrarre uno o più attributi (colonne) da una relazione.

Data una relazione R e un insieme di attributi A = {A₁, A₂, ..., Aₖ}, la proiezione restituisce una nuova relazione contenente esclusivamente gli attributi selezionati.

L'operazione di proiezione si indica con il simbolo:

πA₁,A₂,...,Aₖ(R)

La relazione ottenuta:

  • contiene soltanto gli attributi richiesti;
  • elimina gli attributi non selezionati;
  • elimina automaticamente eventuali tuple duplicate.

Esempio

Supponiamo di avere la relazione Clienti(Codice, Nome, Cognome, Indirizzo, Provincia)

CODICE NOME COGNOME INDIRIZZO PROVINCIA
C001 Mario Rossi Via Adige, 30 MI
C002 Paolo Bianchi Via Roma, 12 MI
C003 Luigi Verdi Via Moro, 4 TO

Applicando la proiezione sugli attributi Nome e Cognome

πNome,Cognome(Clienti)

si ottiene:

NOME COGNOME
Mario Rossi
Paolo Bianchi
Luigi Verdi

Eliminazione dei duplicati

Supponiamo ora che due clienti abbiano lo stesso nome e cognome.

Nome Cognome
Mario Rossi
Mario Rossi
Paolo Bianchi

Dopo la proiezione, il risultato sarà:

Nome Cognome
Mario Rossi
Paolo Bianchi

Infatti, nell'algebra relazionale una relazione non può contenere tuple duplicate.

Nota: La proiezione non seleziona le righe, ma le colonne della relazione.


5. Selezione (o Restrizione) di una relazione

La selezione, detta anche restrizione, è l'operazione che permette di scegliere le tuple che soddisfano una determinata condizione.Data una relazione R e un predicato P, la selezione restituisce una nuova relazione contenente esclusivamente le tuple per cui il predicato risulta vero. L'operazione di selezione si indica con il simbolo:

σP(R)


Esempio

Consideriamo ancora la relazione Clienti(Codice, Nome, Cognome, Indirizzo, Provincia)

CODICE NOME COGNOME INDIRIZZO PROVINCIA
C001 Mario Rossi Via Adige, 30 MI
C002 Paolo Bianchi Via Roma, 12 MI
C003 Luigi Verdi Via Moro, 4 TO
C004 Guido Galli Via Po, 23 PD

Per selezionare i clienti residenti nella provincia di Milano si esegue la seguente operazione:

σProvincia = "MI"(Clienti)

Il risultato è:

CODICE NOME COGNOME INDIRIZZO PROVINCIA
C001 Mario Rossi Via Adige, 30 MI
C002 Paolo Bianchi Via Roma, 12 MI

Predicati semplici e composti

La condizione di selezione prende il nome di predicato. Un predicato semplice utilizza un solo operatore di confronto. Ad esempio:

Provincia = "MI"

oppure

Importo > 100

Un predicato composto combina più condizioni mediante operatori logici.

Ad esempio:

Provincia = "MI" AND Cognome = "Bianchi"

oppure

Provincia = "MI" OR Provincia = "RM"

Proiezione e selezione

È facile confondere questi due operatori. Per ricordarne il significato basta pensare che:

  • la proiezione sceglie le colonne;
  • la selezione sceglie le righe.

Questa è probabilmente la distinzione più importante da ricordare quando si studia l'algebra relazionale.


6. Prodotto di relazioni

Date due relazioni qualsiasi R e S, rispettivamente di grado g₁ e g₂ e di cardinalità c₁ e c₂, il prodotto cartesiano è la relazione ottenuta combinando ogni tupla di R con ogni tupla di S. L'operazione è indicata con il simbolo:

R × S

La relazione risultante ha:

  • grado pari a g₁ + g₂, perché contiene tutti gli attributi delle due relazioni;
  • cardinalità pari a c₁ × c₂, perché ogni tupla della prima relazione viene combinata con tutte le tuple della seconda.

Esempio: supponiamo di avere le seguenti relazioni.

Ordini

COD_ORD DATA COD_CLI
001 20/10/2015 1000
002 23/10/2015 2000

Articoli

COD_ART PREZZO QTA
A001 10 500
A002 20 400
A003 30 300

Applicando il prodotto cartesiano

Ordini × Articoli

si ottiene una relazione contenente 2 × 3 = 6 tuple. Ogni ordine viene associato a tutti gli articoli, indipendentemente dal fatto che esista o meno una relazione tra essi.

COD_ORD DATA COD_CLI COD_ART PREZZO QTA
001 20/10/2015 1000 A001 10 500
001 20/10/2015 1000 A002 20 400
001 20/10/2015 1000 A003 30 300
002 23/10/2015 2000 A001 10 500
002 23/10/2015 2000 A002 20 400
002 23/10/2015 2000 A003 30 300

Osservazione

Nel prodotto cartesiano non esiste alcuna condizione di collegamento tra le due relazioni. Per questo motivo il risultato contiene tutte le possibili combinazioni delle tuple delle due tabelle. Nella pratica, una relazione ottenuta mediante il solo prodotto cartesiano ha raramente un significato utile. Sebbene venga utilizzato raramente da solo, il prodotto cartesiano è uno degli operatori fondamentali dell'algebra relazionale. Infatti, molti altri operatori possono essere definiti a partire da esso. In particolare, una join può essere vista come:

  1. il prodotto cartesiano delle due relazioni;
  2. la selezione delle tuple che soddisfano una determinata condizione;
  3. (nel caso della join naturale) l'eliminazione degli attributi duplicati.

Dal punto di vista teorico, la join può essere descritta come un prodotto cartesiano seguito da una selezione. Tuttavia, nei moderni sistemi di gestione di basi di dati, questa operazione non viene quasi mai eseguita materialmente. Il motore del database utilizza algoritmi molto più efficienti, come Nested Loop Join, Merge Join e Hash Join, che evitano di generare tutte le combinazioni possibili tra le tuple.


7. Join di due relazioni

La join è l'operazione più importante dell'algebra relazionale. Consente di combinare le tuple appartenenti a due relazioni diverse sulla base di una condizione di confronto tra i loro attributi. Grazie alla join è possibile ricostruire informazioni che, durante la progettazione del database, sono state suddivise in più tabelle per evitare ridondanze. Nella maggior parte dei casi, la condizione di join confronta una chiave primaria con una chiave esterna.


Esempio: consideriamo le relazioni:

Giocatore(IdGiocatore, Nome, Cognome)

IdGiocatore Nome Cognome
1 Mario Rossi
2 Luca Bianchi
3 Paolo Verdi

Penalità(IdPenalita, Data, Importo, IdGiocatore)

IdPenalita Data Importo IdGiocatore
001 10/10/2015 100 1
002 11/10/2015 500 2

L'attributo IdGiocatore è:

  • chiave primaria nella relazione Giocatore;
  • chiave esterna nella relazione Penalità.

La join consente di associare ogni penalità al giocatore a cui appartiene.


Come si può definire una join? Dal punto di vista teorico, una join può essere descritta come una sequenza di operazioni dell'algebra relazionale:

  1. si calcola il prodotto cartesiano delle due relazioni;
  2. si selezionano le tuple che soddisfano la condizione di join;
  3. se necessario, si eliminano gli attributi duplicati.

Questa descrizione è utile per comprendere la teoria dell'algebra relazionale. Nei DBMS reali, invece, il motore del database utilizza algoritmi di ottimizzazione che evitano di costruire esplicitamente il prodotto cartesiano.


7.1 Join naturale (Natural Join)

La join naturale è una particolare forma di join che mette automaticamente in relazione due tabelle utilizzando tutti gli attributi aventi lo stesso nome e appartenenti allo stesso dominio. L'operazione è indicata con il simbolo:

R ⋈ S

Il risultato contiene tutte le coppie di tuple che hanno lo stesso valore negli attributi comuni. Gli attributi utilizzati per il confronto compaiono una sola volta nella relazione finale.


Esempio

Consideriamo le relazioni Giocatore e Penalità. Entrambe contengono l'attributo IdGiocatore, che identifica il giocatore. Poiché questo attributo ha lo stesso nome nelle due relazioni e appartiene allo stesso dominio, è possibile applicare l'operatore di Join Naturale.

Giocatore ⋈ Penalità

produce:

Nome Cognome IdGiocatore IdPenalita Data Importo
Mario Rossi 1 001 10/10/2015 100
Luca Bianchi 2 002 11/10/2015 500

La Join Naturale associa automaticamente ogni giocatore alle eventuali penalità ricevute, confrontando i valori dell'attributo IdGiocatore. Nel risultato compare una sola colonna IdGiocatore, poiché gli attributi omonimi delle due relazioni vengono unificati. I giocatori che non hanno alcuna penalità e le penalità prive di un giocatore corrispondente non compaiono nel risultato.


Osservazione: la join naturale utilizza automaticamente tutti gli attributi comuni. Per questo motivo è opportuno usarla solo quando tali attributi rappresentano realmente la relazione tra le due tabelle.

Osservazione: molti manuali consigliano di evitare la NATURAL JOIN nei programmi reali. Il motivo è semplice: se in futuro due tabelle acquisiscono un nuovo attributo con lo stesso nome, la NATURAL JOIN cambia automaticamente comportamento, con il rischio di produrre risultati inattesi. Per questo, nella pratica, si preferiscono quasi sempre le INNER JOIN con una clausola ON esplicita, ad esempio:

SELECT *
FROM Clienti
JOIN Agenti
ON Clienti.CodAgente = Agenti.CodAg;

7.2 Theta Join ed EquiJoin

La Theta Join è la forma più generale di join. La condizione di confronto può utilizzare uno qualsiasi degli operatori relazionali: =, <, <=, >, < =, <>.

In forma generale si scrive:

R ⋈θ S

dove θ rappresenta una qualsiasi condizione di confronto: (=, , <, , >, ).


L'EquiJoin è una particolare Theta Join nella quale la condizione di confronto utilizza esclusivamente l'operatore di uguaglianza (=).

In forma generale si scrive:

R ⋈R.A=S.B S

Supponiamo di avere una relazione Clienti e una relazione Agenti. Un Cliente si riferisce ad un solo agente e un agente puo' avere piu' clienti, cioe' Agenti-Clienti e' una associazione 1:N. L'operazione:

Clienti ⋈Clienti.CodAgente=Agenti.CodAg Agenti

è una join tra le relazioni Clienti e Agenti. In questo caso la condizione della join è: Clienti.CodAgente = Agenti.CodAg. Poiché la condizione utilizza l'operatore di uguaglianza, questa operazione è una EquiJoin.

Il risultato associa ogni cliente all'agente che lo segue, riportando in un'unica relazione le informazioni presenti nelle due tabelle.

Esempio:

Clienti

CodCli NomeCli Indirizzo CodAgente
C001 Bianchi Mario Via Po, 23 A0052
C002 Neri Paolo Via Roma, 12 A0016
C006 Verdi Luigi Via Moro, 4 A0052

Agenti

CodAg NomeAg Telefono
A0016 Franchi Luca 346 1736449
A0044 Livi Claudio 339 1837447
A0052 Bini Sergio 333 1234935

Applicando l'EquiJoin si ottiene:

CodCli NomeCli Indirizzo CodAgente NomeAg Telefono
C001 Bianchi Mario Via Po, 23 A0052 Bini Sergio 333 1234935
C002 Neri Paolo Via Roma, 12 A0016 Franchi Luca 346 1736449
C006 Verdi Luigi Via Moro, 4 A0052 Bini Sergio 333 1234935

Join naturale ed EquiJoin

È importante non confondere questi due operatori. Ogni Natural Join è un'EquiJoin, perché confronta attributi mediante l'operatore di uguaglianza. Tuttavia, non tutte le EquiJoin sono Natural Join. Infatti:

  • l'EquiJoin richiede che il programmatore specifichi esplicitamente la condizione di confronto e mantiene gli attributi ulitizzati per il confronto
  • la Natural Join individua automaticamente gli attributi comuni ed elimina le colonne duplicate.

7.3 Outer Join (Join Esterna)

La Natural Join, la Theta Join e la EquiJoin sono dette join interne (inner join). Una join interna restituisce solo le tuple per le quali esiste una corrispondenza tra le relazioni coinvolte, cioè quelle che soddisfano la condizione di join.

Una join esterna (outer join), invece, oltre alle tuple che soddisfano la condizione di join, restituisce anche quelle prive di una corrispondenza nell'altra relazione, completando gli attributi mancanti con valori NULL.

Esistono tre tipi di join esterna:

  • Left Outer Join (join esterna sinistra) R ⟕ S
  • Right Outer Join (join esterna destra) R ⟖ S
  • Full Outer Join (join esterna completa) R ⟗ S

La Left Outer Join (join esterna sinistra) restituisce: tutte le tuple della relazione posta a sinistra dell'operatore, le tuple corrispondenti della relazione posta a destra; per le tuple della relazione sinistra che non trovano alcuna corrispondenza, gli attributi della relazione destra assumono valore NULL.

Ad esempio, l'operazione Giocatore ⟕ Penalita restituisce tutte le tuple della inner join e in piu anche la riga con i giocatori senza penalita, con il campo penalita non valorizzato, cioe NULL.

IdGiocatore Nome Cognome IdPenalita Data Importo
1 Mario Rossi 001 10/10/2015 100
2 Luca Bianchi 002 11/10/2015 500
3 Paolo Verdi NULL NULL NULL

Ad esempio, se alcuni clienti non hanno ancora un agente assegnato, la Left Outer Join consente comunque di visualizzarli nel risultato.


La Right Outer Join (join esterna destra) funziona in modo analogo, ma mantiene tutte le tuple della relazione posta a destra dell'operatore.

Se una tupla della relazione destra non trova alcuna corrispondenza nella relazione sinistra, gli attributi della relazione sinistra vengono completati con valori NULL.


Ad esempio, nel caso delle relazioni Clienti e Agenti, tutti i clienti hanno un agente, ma ci sono anche agenti a cui non e' stato assegnato nessun cliente. Per cui l'operazione Clienti ⟖ Agenti mostra tutti gli agenti anche l'agente "Livi Claudio" che non ha clienti associati.

CodCli NomeCli Indirizzo CodAgente NomeAg Telefono
C001 Bianchi Mario Via Po, 23 A0052 Bini Sergio 333 1234935
C002 Neri Paolo Via Roma, 12 A0016 Franchi Luca 346 1736449
C006 Verdi Luigi Via Moro, 4 A0052 Bini Sergio 333 1234935
NULL NULL NULL A0044 Livi Claudio 339 1837447

Se facessi Giocatori ⟖ Penalita avrei lo stesso risultato della equijoin.


La Full Outer Join (join esterna completa) combina i comportamenti delle due precedenti.

Il risultato contiene:

  • tutte le tuple della relazione sinistra;
  • tutte le tuple della relazione destra;
  • le tuple corrispondenti vengono unite;
  • le tuple prive di corrispondenza vengono comunque mantenute, completando gli attributi mancanti con valori NULL.

Esempio: applicazione di outer join

Durante la propria attività professionale, il professore si è trovato ad analizzare archivi relativi ai versamenti dell'ICI contenenti errori di inserimento.

La prima tabella rappresentava l'anagrafe dei contribuenti e aveva il CodiceFiscale come chiave primaria. La seconda tabella conteneva i versamenti effettuati dai contribuenti e utilizzava CodiceFiscale come chiave esterna, poiché uno stesso contribuente può effettuare più versamenti nel corso del tempo. A causa di errori nell'inserimento dei dati, il database presentava alcune anomalie. In particolare: erano presenti contribuenti ai quali non risultava associato alcun versamento; erano presenti versamenti il cui codice fiscale non corrispondeva ad alcun contribuente presente nell'anagrafe. Situazioni di questo tipo possono essere individuate facilmente mediante le outer join, che consentono di evidenziare anche le tuple prive di una corrispondenza nell'altra relazione.

Ritorniamo ora agli esempi presentati nei paragrafi precedenti.

Nell'associazione Clienti–Agenti, per visualizzare tutti gli agenti che non hanno clienti assegnati, si utilizza una Right Outer Join tra le relazioni Clienti e Agenti. Successivamente si selezionano le tuple nelle quali gli attributi provenienti dalla relazione Clienti risultano NULL. Queste tuple rappresentano gli agenti ai quali non è associato alcun cliente.

Nell'associazione Giocatore–Penalità, invece, per ottenere l'elenco dei giocatori che non hanno ricevuto alcuna penalità, si utilizza una Left Outer Join tra le relazioni Giocatore e Penalità. Si selezionano quindi le tuple nelle quali gli attributi provenienti dalla relazione Penalità risultano NULL. Tali tuple identificano i giocatori ai quali non è associata alcuna penalità.

In SQL:

SELECT *
FROM Clienti
RIGHT OUTER JOIN Agenti
    ON Clienti.CodAgente = Agenti.CodAg
WHERE Clienti.CodCliente IS NULL;

e

SELECT *
FROM Giocatore
LEFT OUTER JOIN Penalità
    ON Giocatore.IdGiocatore = Penalità.IdGiocatore
WHERE Penalità.IdGiocatore IS NULL;

Dal concetto teorico dell'Outer Join, si passa alla tecnica pratica più comune per individuare i record "orfani" in una base di dati.


Alcuni esempi di operazioni dell'algebra relazionale e la loro traduzione in linguaggio SQL:

Operazione dell'algebra relazionale Costrutto SQL corrispondente
Unione R ∪ S SELECT ... FROM ... UNION SELECT ... FROM ...
Per mantenere anche i duplicati si utilizza UNION ALL.
Intersezione R ∩ S SELECT ... FROM ... INTERSECT SELECT ... FROM ...
Differenza R − S SELECT ... FROM ... EXCEPT SELECT ... FROM ...
Proiezione πNome,Cognome(Clienti) SELECT Nome, Cognome FROM Clienti;
Per eliminare i duplicati è necessario utilizzare SELECT DISTINCT.
Selezione σProvincia='MI'(Clienti) SELECT * FROM Clienti WHERE Provincia = 'MI';
Prodotto cartesiano Ordini × Articoli SELECT * FROM Ordini CROSS JOIN Articoli;
Natural Join Giocatore ⋈ Penalità SELECT * FROM Giocatore NATURAL JOIN Penalità;
Nella pratica è poco utilizzata; si preferisce quasi sempre INNER JOIN ... ON ....
EquiJoin Clienti ⋈Clienti.CodAgente = Agenti.CodAg Agenti
SELECT * FROM Clienti INNER JOIN Agenti 
    ON Clienti.CodAgente = Agenti.CodAg;
Left Outer Join Giocatore ⟕ Penalità
SELECT * FROM Giocatore LEFT OUTER JOIN Penalità 
    ON Giocatore.IdGiocatore = Penalità.IdGiocatore;
La parola OUTER è facoltativa: si può scrivere anche semplicemente LEFT JOIN.
Right Outer Join Clienti ⟖ Agenti
SELECT * FROM Clienti RIGHT OUTER JOIN Agenti
    ON Clienti.CodAgente = Agenti.CodAg;
Anche in questo caso OUTER è facoltativo.
Full Outer Join R ⟗ S SELECT * FROM R FULL OUTER JOIN S ON ...;
Non è supportata da tutti i DBMS.

8. Esempi di applicazione degli operatori dell'algebra relazionale

Consideriamo il seguente frammento di schema di database di una filiale di una banca, con le tabella Cliente, ContoCorrente e Movimento. Un cliente puo' avere piu' conti correnti (non e' possibile cointestare un conto) e su un conto corrente si possono fare piu' movimenti. Se c'e' un conto corrente, sicuramente c'e' una persona che lo possiede, se c'e' un movimento, sicuramente e' legato ad un conto corrente e contemporameamente ad una persona.

 

Consideriamo il seguente frammento di schema di una base di dati bancaria.

Clienti(
    IdCliente, 
    Cognome, 
    Nome, 
    Via, 
    CAP, 
    Citta, 
    Provincia
    )
ContoCorrenti(
    CodConto, 
    IdCliente(FK), 
    DataApertura, 
    DataChiusura, 
    Saldo
    )
Movimenti(
    IdMovimento, 
    CodConto(FK), 
    Data, 
    Importo, 
    Causale
    ) 

Nella relazione ContoCorrenti, IdCliente è una chiave esterna che fa riferimento alla relazione Clienti. Nella relazione Movimenti, CodConto è una chiave esterna che fa riferimento alla relazione ContoCorrenti. Gli esempi seguenti mostrano come gli operatori dell'algebra relazionale possano essere combinati per formulare interrogazioni anche complesse. Per ogni interrogazione viene riportata anche la corrispondente espressione SQL.


Esempio 1

Richiesta

Visualizzare la causale e l'importo dei movimenti aventi importo superiore a 5000 euro.

Algebra relazionale

πCausale, ImportoImporto>5000(Movimenti))

SQL

SELECT Causale, Importo
FROM Movimenti
WHERE Importo > 5000;

In questo esempio vengono utilizzati soltanto due operatori: la selezione, che individua i movimenti con importo superiore a 5000 euro e la proiezione, che mantiene soltanto gli attributi Causale e Importo.


Esempio 2

Richiesta

Visualizzare il codice del conto e l'importo dei movimenti effettuati dal cliente Mario Bianchi.

Algebra relazionale

Per semplicità definiamo dapprima la relazione

 R = Clienti ⋈Clienti.IdCliente=ContoCorrenti.IdCliente ContoCorrenti 

L'interrogazione diventa

πCodConto, ImportoCognome=′Bianchi′∧Nome=′Mario′ (R ⋈R.CodConto=Movimenti.CodContoMovimenti))

SQL

SELECT ContoCorrenti.CodConto,
       Movimenti.Importo
FROM Clienti
INNER JOIN ContoCorrenti
    ON Clienti.IdCliente = ContoCorrenti.IdCliente
INNER JOIN Movimenti
    ON ContoCorrenti.CodConto = Movimenti.CodConto
WHERE Cognome='Bianchi'
  AND Nome='Mario';

L'interrogazione utilizza due join per collegare le tre tabelle della base di dati. Successivamente vengono selezionate le tuple del cliente richiesto e infine viene eseguita la proiezione degli attributi da visualizzare.


Esempio 3

Richiesta

Visualizzare il cognome e il nome dei clienti che hanno effettuato movimenti con causale "Vers" nel mese di settembre 2006.

Algebra relazionale

Definiamo le relazioni intermedie

R = Clienti ⋈Clienti.IdCliente=ContoCorrenti.IdCliente ContoCorrenti
S = R ⋈R.CodConto=Movimenti.CodConto Movimenti

L'interrogazione è

πCognome, NomeCausale=′Vers′∧Data≥01/09/2006∧Data≤30/09/2006(S))

SQL

SELECT Clienti.Cognome,
       Clienti.Nome
FROM Clienti
INNER JOIN ContoCorrenti
    ON Clienti.IdCliente = ContoCorrenti.IdCliente
INNER JOIN Movimenti
    ON ContoCorrenti.CodConto = Movimenti.CodConto
WHERE Causale = 'Vers'
  AND Data >= '2006-09-01'
  AND Data <= '2006-09-30';

Osservazione

L'interrogazione mostra come sia possibile costruire interrogazioni complesse componendo più operatori elementari dell'algebra relazionale.


Esempio 4

Consideriamo ora il database utilizzato negli esempi precedenti, costituito dalle relazioni Giocatore e Penalità.

Richiesta

Visualizzare la data e l'importo delle penalità del giocatore Mario Rossi.

Algebra relazionale

πData,ImportoCognome=′Rossi′∧Nome=′Mario′(Giocatore⋈Giocatore.IdGiocatore=Penalitaˋ.IdGiocatorePenalitaˋ))

SQL

SELECT Data,
       Importo
FROM Giocatore
INNER JOIN Penalità
    ON Giocatore.IdGiocatore = Penalità.IdGiocatore
WHERE Cognome='Rossi'
  AND Nome='Mario';

La stessa interrogazione può essere scritta anche utilizzando la sintassi SQL meno recente:

SELECT Data,
       Importo
FROM Giocatore, Penalità
WHERE Giocatore.IdGiocatore = Penalità.IdGiocatore
  AND Cognome='Rossi'
  AND Nome='Mario';

Nota: le due interrogazioni sono equivalenti. Tuttavia, oggi è consigliabile utilizzare la sintassi con INNER JOIN, perché separa chiaramente la condizione di join (ON) dalle condizioni di ricerca (WHERE), rendendo il codice più leggibile e meno soggetto a errori.


Gli esempi mostrano come le interrogazioni vengano costruite combinando pochi operatori fondamentali dell'algebra relazionale:

  • join, per collegare le relazioni della base di dati;
  • selezione, per individuare le tuple di interesse;
  • proiezione, per scegliere gli attributi da visualizzare.

Il linguaggio SQL implementa questi stessi concetti attraverso le clausole JOIN, WHERE e SELECT. Comprendere l'algebra relazionale permette quindi di interpretare meglio il funzionamento delle interrogazioni SQL e di progettare query corrette ed efficienti.

No comments:

Post a Comment