English
Relational Algebra: self-join + set subtraction
In Relational Algebra exercises, it may happen that is asked
something like “detect the minimum/maximum of the values for a table
attribute”, or something of different nature, but that may be traced
back to these.
The solution in these cases is using a “self-join” followed by a “set
difference”.
This document will explain what’s the logical reasoning that justify the
usage of these two operations.
It is took for granted that the reader knows Relational Algebra
well.
Consider the following example table T, defined as
T(A), with tuples:
+===+
| A |
+===+
| 1 |
| 2 |
| 3 |
| 4 |
+---+
The request is: “Find the minimum value for A in
T”.
A quick glance suggests that the value of interest is 1, but how to get
to the result with Relational Algebra?
To solve this kind of problem, one must imagine the values for A, as
if they were a set S = {1, 2, 3, 4}, and then, consider its
cartesian product SxS:
SxS = {
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(2, 1),
(2, 2),
(2, 3),
(2, 4),
(3, 1),
(3, 2),
(3, 3),
(3, 4),
(4, 1),
(4, 2),
(4, 3),
(4, 4)
}
Now, imagine to filter these pairs in respect to the condition
LT > RT (left term > right term); The result of said
filtering is the following relation R_>:
R_> = {
(2, 1),
(3, 1),
(3, 2),
(4, 1),
(4, 2),
(4, 3),
}
Paying attention to the LTs of R_>, one
may notice there’s no pair for which LT = 1.
The value of interest is missing, but that’s the point, thanks
to this, the set difference can finally be used.
Let K = {2, 3, 4}, that is, the set of LTs in
R_>; All that is left, is to subtract K
from S:
S - K = {1, 2, 3, 4} - {2, 3, 4} = {1}
Wow, the minimum has been found!
In Relational Algebra, this is translated as self-join (=theta join
of T with a renamed copy of it) of T,
subtracted (set difference) from T itself.
Ti solve the quesit, it is sufficient to use the following
operations:
K := π_{A}(T ⋈_{A > A'} ρ_{A'/A}(T));
r := T - K
Please note that the notation _{...} indicates the
subscript of an operator (the contents being in braces).
For example, the operation ρ_{A'/A}(T) is read as “rename
the attribute A for table T as A’”, “A’/A” is in the subscript of
ρ and T is in round brackets.
Here r is the wanted result.
When there is an order among values (the so-called “order relation”), a
self-join with a condition like LT op RT, followed by a set
subtraction, is usually sufficient to solve this particular class of
problems.
The comparison operator op depends strictly on the results
one wants to get.
Self-join is thus, the relational equivalent of comparing all the
possible values of set S among themselves; It’s obvious
that if the greater values are asked, THERE WILL NEVER BE the minimum in
LT, bacause it is the only value which IS NOT GREATER than
the others; In the same manner, if the lower values are asked, THERE
WILL NEVER BE the maximum in LT, because it IS NOT LOWER
than the others.
This helps in understanding why one needs the self-join first and
then the subtraction: Self-join’s purpose is to accumulate useless
values as LTs, so that later, it will be possible to
subtract them from the table that serves as a whole, in order
to get the values of interest as result.
In case of minimum/maximum detection, the reasoning can be summarized in:
- To detect the minimum, first self-join with condition
LT > RT, then, subtract the result from the set ofLTs; - To detect the maximum, first self-join with condition
LT < RT, then, subtract the result from the set ofLTs;
More complex problem solvable with self-join + subtraction
Here follows the discussion of a more complex problem, which can be
traced back to the previous solving reasoning.
Suppose the database has the following tables with constraints:
Organization(ID, Name);
Person(ID, Name, Gender);
Employee(IDOrganization, IDPerson);
ID is primary key for Organization;
ID is primary key for Person;
Attributes tuple (IDOrganization, IDPerson) is primary key for Employee;
IDPerson references Person(ID);
IDOrganization references Organization(ID);
It is asked to “Return the organizations that exclusively employ
women”.
This means that all organizations that employ a mixed workforce, must be
excluded.
Despite it not being a minimum/maximum problem, the reasoning is the
same: At first, a self-join is needed, in order to get the set of
organizations that have a mixed workforce (that is, the useless
tuples).
To do this, one can make the view v_1, defined as:
v_1 = π_{IDOrganization, Gender}(Employee ⋈_{IDPerson = ID} Person);
This view collects the organization IDs and the gender of the
employees in a single table.
Now it’s time for the self-join: The employees (in actuality, only their
genders) belonging to the same organization, must be combined with each
other, in order to find the tuples, in which the two employees have
opposite genders.
This works because, when an employee is combined with the colleagues,
and all of them have the same gender, it is guaranteed that there won’t
be tuples where the first employee is of the opposite gender to the
second one.
To get this result, a self-join of v_1 is needed:
v_2 = π_{IDOrganization}(v_1 ⋈_{Gender ≠ Gender' ^ IDOrganization = IDOrganization'} ρ_{IDOrganization',Gender'/IDOrganization,Gender}(v_1))
v_2 collects the organizations (IDs) that employ both
genders, that is, the useless tuples.
It’s now time to subtract v_2 from v_1, in
order to get v_3, that is, a view containing all the
organizations (IDs) which exclusively employ men or women, not both:
v_3 = π_{IDOrganization}(v_1) - v_2
It’s not over yet, it was asked to return the organizations (IDs)
that exclusively employ women.
To overcome the obstacle, it sufficient to use a theta-join between
v_3 and v_1, in order to exclude male
employees.
The final operation is, thus, the following:
r = π_{IDOrganization}(v_3 ⋈ {Gender ≠ 'M' ^ IDOrganization = IDOrganization'} ρ_{IDOrganization'/IDOrganization}(v_1))
r is the desired result, that is, the set of
organizations (IDs) that exclusively employ women.
Italiano
Algebra relazionale: self-join + sottrazione insiemistica
Negli esercizi di Algebra relazionale, può capitare che vengano fatte
richieste del tipo “individua il minimo/massimo dei valori per un
attributo di tabella”, o di altra natura ma riconducibili a
queste.
Questi esercizi sono risolvibili sfruttando un “self-join” seguito da
una “differenza insiemistica”.
Nel documento viene spiegato qual’è il ragionamento logico che
giustifica l’uso di queste due operazioni.
Si da per scontato che il lettore conosca bene l’algebra
relazionale.
Si consideri la seguente tabella T d’esempio, definita come
T(A) e con tuple:
+===+
| A |
+===+
| 1 |
| 2 |
| 3 |
| 4 |
+---+
La richiesta è: “Trova il valore minimo per A nella tabella
T”.
Una semplice occhiata suggerisce che tale valore è 1, ma come si giunge
a questo risultato con l’algebra relazionale?
Per risolvere questo tipo di problema, occorre aver presente i valori
per A, come fossero un insieme S = {1, 2, 3, 4}, e quindi
considerarne il prodotto cartesiano SxS:
SxS = {
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(2, 1),
(2, 2),
(2, 3),
(2, 4),
(3, 1),
(3, 2),
(3, 3),
(3, 4),
(4, 1),
(4, 2),
(4, 3),
(4, 4)
}
Ora, si immagini di filtrare queste coppie rispetto alla condizione
LT > RT (termine sinistro > termine destro); Il
risultato di tale filtraggio è la seguente relazione
R_>:
R_> = {
(2, 1),
(3, 1),
(3, 2),
(4, 1),
(4, 2),
(4, 3),
}
Ponendo l’attenzione sui diversi LT di
R_>, si constata che non esiste alcuna coppia per cui
LT = 1.
Il valore di interessa manca, ma è questo il punto, grazie a
ciò, sarà possibile usare la sottrazione insiemistica.
Sia K = {2, 3, 4}, ovvero, l’insieme degli LT
di R_>; Rimane solo da sottrarre K da
S:
S - K = {1, 2, 3, 4} - {2, 3, 4} = {1}
Toh, è stato trovato il minimo!
In algebra relazionale, questo si traduce in un self-join (=theta
join di T con una sua copia rinominata) di T,
sottratto (differenza insiemistica) da T stesso.
Per soddisfare la richiesta, si utilizzano le seguenti operazioni:
K := π_{A}(T ⋈_{A > A'} ρ_{A'/A}(T));
r := T - K
Si noti che la notazione _{...} indica i contenuti (tra
parentesi graffe) del pedice del particolare operatore.
Ad esempio, l’operazione ρ_{A'/A}(T) si legge come
“rinomina l’attributo A di T in A’”, “A’/A” si trova nel pedice di
ρ e T è fra parentesi tonde.
Qui r è il risultato desiderato.
Quando si ha un ordine tra valori (la cosiddetta “relazione d’ordine”),
un self-join con una condizione del tipo LT op RT, seguito
da una sottrazione insiemistica, di solito sono sufficienti per
risolvere questa particulare classe di problemi .
L’operatore di comparazione op dipende strettamente dal
risultato che si vuole ottenere.
Il self-join è quindi, l’equivalente relazionale del comparare tutti
i singoli valori dell’insieme S tra loro; È ovvio che se si
chiedono i valori maggiori, NON SI AVRÀ MAI il minimo in
LT, perchè appunto, è l’unico valore che NON È MAGGIORE
degli altri; Allo stesso modo, chiedendo tutti i valori minori, NON SI
AVRÀ MAI il massimo in LT, perchè NON È MINORE degli
altri.
Questo permette di capire perchè serve prima il self-join e poi la
sottrazione: Il self-join ha lo scopo di accumulare i valori
inutili come LT, cosicchè dopo, sia possibile
sottrarli dalla tabella che fa da intero, per ottenere i
valori di interesse come risultato.
Nel caso dell’individuazione del minimo/massimo, il ragionamento si riassume in:
- Per individuare il minimo, prima usare il self-join con condizione
LT > RT, quindi sottrarre il risultato dall’insieme degliLT; - Per individuare il massimo, prima usare il self-join con condizione
LT < RT, quindi sottrarre il risultato dall’insieme degliLT;
Problema più complesso risolvibile mediante self-join + sottrazione
Qui segue la discussione di un problema più complesso, che può essere
ricondotto al precedente ragionamento di risoluzione.
Si supponga che la base di dati presenti le seguenti tabelle con
vincoli:
Azienda(ID, Nome);
Persona(ID, Nome, Sesso);
Impiegato(IDAzienda, IDPersona);
ID è chiave primaria per Azienda;
ID è chiave primaria per Persona;
La tupla di attributi (IDAzienda, IDPersona) è chiave primaria per Impiegato;
IDPersona fa riferimento a Persona(ID);
IDAzienda fa riferimento a Azienda(ID);
Viene quindi richiesto di “Restituire le aziende che impiegano solo
donne”.
Questo significa che vanno escluse tutte le aziende che hanno una forza
lavoro mista.
Sebbene non si tratti di un minimo/massimo, il ragionamento è lo stesso:
Occorre dapprima usare un self-join, per prelevare l’insieme delle
aziende con impiegati misti (ergo, le tuple inutili).
Per fare ciò, è possibile creare una vista v_1, definita
come:
v_1 = π_{IDAzienda, Sesso}(Impiegato ⋈_{IDPersona = ID} Persona);
Con questa vista, abbiamo nella stessa tabella sia l’ID dell’azienda
che il sesso dell’impiegato.
Ora tocca al self-join: Gli impiegati (soltanto i loro sessi, a dire il
vero), appartenenti alla stessa azienda, devono essere combinati l’uno
con l’altro, allo scopo di individuare le tuple, i cui due impiegati
hanno sessi opposti.
Ciò funziona perchè, quando un impiegato viene combinato con i suoi
colleghi, ed essi sono tutti dello stesso sesso, non accadrà mai che in
una tupla, si avrà che il primo impiegato ha un sesso opposto rispetto
al secondo.
Per ottenere questo risultato, occorre un self-join di
v_1:
v_2 = π_{IDAzienda}(v_1 ⋈_{Sesso ≠ Sesso' ^ IDAzienda = IDAzienda'} ρ_{IDAzienda',Sesso'/IDAzienda,Sesso}(v_1))
v_2 raccoglie tutti gli ID di aziende che impiegano ambo
i sessi, ovvero, le tuple inutili.
Ora si passa alla sottrazione insiemistica di v_2 da
v_1, di modo da ottenere una vista v_3,
contenente gli ID di aziende che hanno impiegati di un solo sesso:
v_3 = π_{IDAzienda}(v_1) - v_2
Non è ancora finita però, la richiesta vuole le aziende che impiegano
soltanto donne.
Per superare quest’ostacolo, è sufficiente usare un theta join tra
v_3 e v_1, di modo da escludere gli impiegati
di sesso maschile.
L’operazione finale è quindi la seguente:
r = π_{IDAzienda}(v_3 ⋈ {Sesso ≠ 'M' ^ IDAzienda = IDAzienda'} ρ_{IDAzienda'/IDAzienda}(v_1))
r è il risultato desiderato, ovvero, l’insieme degli ID
di aziende che impiegano solo donne.