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:
- hanno lo stesso numero di attributi (lo stesso grado);
- 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:
- il prodotto cartesiano delle due relazioni;
- la selezione delle tuple che soddisfano una determinata condizione;
- (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:
- si calcola il prodotto cartesiano delle due relazioni;
- si selezionano le tuple che soddisfano la condizione di join;
- 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, Importo(σImporto>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, Importo (σCognome=′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, Nome(σCausale=′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,Importo(σCognome=′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