---
title: "Base de données avancées : Algèbre relationnelle"
date: 2022-01-12
tags: ["schema", "algèbre relationnelle", "relation"]
categories: ["Base de données avancées", "Cours"]
mathjax: true
---

L'agèbre relationnelle est un langage de requêtes dans une base de donnée
relationelle. Inventé par Edgar F. Codd en 1970, il représente le fondement 
théorique du langage SQL.


C'est un langage procédural : les requêtes sont des suites d'opérations qui
construise la réponse.Il permet la manipulation des relations par interrogation
en combiant les relations avec différents opérateurs afin d'obtenir de nouvelles
relations.

## La projection

La projection permet de ne garder que les *n_uplets* des attibuts indiqué par
l'opérateur en supprimant les éventuels doublons. Il est noté \\(\pi\\), son
équivalent SQL est `SELECT`. On parle alors de *partition verticale*

 * Soit \\(R(\underline{A,B},C,D)\\)
 * La projection des attibuts C et D donne \\(\pi_D(R) = R'(C,D)\\)

## La selection

L'opérateur de  selection (ou restriction) ne permet de retenir que *n_uplets*
vérifiant une condition particulière donnée sous forme de prédicat[^n_predicat].
Il est noté \\(\sigma\\)) et équivaut à la clause `WHERE` en SQL.

 * Soit \\(R(\underline{A,B},C,D)\\)
 * la selection \\(\sigma_{C>2}(R) = R'(A,B,C,D)\\) sélection les ligne de la
     relation \\(R\\) dont \\(C\\) est supérieur à 2

Les opérateurs possibles sont \\(>, <, \geqslant, \leqslant, =, \ne, \subset, 
\subseteq, \nsubseteq \\)

Utilisons les relations de notre exemple de la compagne aérienne, pour trouver
les numéros de séries des avions avec une capacité supérieure à 150 passagers.

\\( \pi_{\text{num_serie}}(\sigma_{capacité > 150}(avions)) \\)


[^n_predicat]:propriété des objets du langage exprimée dans le langage en
question (source [Wikipédia](https://fr.wikipedia.org/wiki/Pr%C3%A9dicat))

## jointure

La jointure (ou jointure naturelle) rapproche deux relations liées par des
attributs communs. Les *n_uplets* du résultat sont obtenus par concaténation des
attributs des deux relations lorsque les attributs communs ont des valeurs
identiques. La jointure est notée \bowtie, son équivalent au `JOIN` en SQL.

 * soit deux relations \\( conso(plat, client) \\) et \\( client(id, nom,
     prénom) \\)
 * \\( \pi_{nom, prénom}(\sigma_{plat = donuts}(conso \bowtie_{conso.client =
     client.id} client)) \\) donne les clients ayant commandé des donuts.

## auto-jointure

L'auto-jointure est la jointure d'une table sur elle-même. elle permet, par
exemple, de calculer une hiérarchie. Lors de l'utilisation de cet operateur, il
faut renommer chaque relation qui compose la jointure de façon unique. Cet

l'opérateur \\( \rho \\) permet de renommer une relation le temps d'une requête.

 * soit une relation \\( employés(matricule, nom, prénom, supérieur) \\)
 * \\( \pi_{D}(\sigma_{nom = Simpson}((employés \bowtie_{employés.matricule = s.D} 
     (\rho{s(A,B,C,D}(employés))) \\) permet de trouver le superieur
     hiérarchique de Simpson.

## Opérations binaires

Les opérations binaires sont des opérations mathématiques standard de la
théories des ensembles. Elles ne peuvent s'appliquer **que sur des relations
compatibles**. On y trouve

 * Union
 * Intersection
 * Différence
 * Division

Pour deux relations \\(A(A_1, A_2, A_3, ..., A_n)\\) et \\(B(B_1, B_2, B_3, ...,
B_n\\) sont **compatibles** si et seulement si elles ont le même degrès
[^n_degres] et si \\(dom(A_i) = dom(B_i)\\) pour \\(1 \leqslant i \leqslant n
\\)

[^n_degres]:le degrés représente le nombre d'attributs d'une relation

### Union

\\(A \cup B\\) est une relation qui inclue tous les *n_uplets* qui
appartiennent à A, B ou au deux. Les doublons sont éliminés.

![Schema représentan l'Union](./images/union.svg)

### Intersection

\\( A \cap B \\) est une relation qui inclue les *n_uplets* appartenant à A et à 
B et seulement ceux-ci.

![Schema représentant l'Intersection](./images/intersection.svg)

### Différence

\\( A - B \\) est une relation qui inclue tous les *n_uplets* appartenant à A
mais pas à B.

![Schema représentant la différence](./images/difference.svg)

Elle répond à la question quel sont les A qui n'ont aucun B.

### Division

La division permet de conserver une sous ensemble de *n_uplets* partie de
\\(R\\) qui sont tous présent dans \\(S\\). Elle permet de répondre à des
questions du type *quel est le truc qui a tous les machins?*.

Pour l'exemple, reprenons notre base de donnée de la compagnie aérienne du
chapitre précédent.

![Notre schéma de base de donnée compagnie
aérienne](../2-introduction_modele_relationnel/images/schema_bdd.svg)

Utilisons la division pour répondre à la question "Quels commandants ont volé
sur tous les type d'avion:

\\[
\Pi_{matricule, type}(
pilotes \underset{pilotes.matricule = planning.matricule}{\bowtie} 
planning \underset{\text{planning.num_avion} = \text{avions.num_serie}}{\bowtie} 
avions) 
\div \Pi_{type}(avion)
\\]

## Calcul relationnel

Le calcul relationnel est un langage formel permettant, tout comme l'algèbre
relationnel, d'exprimer des requêtes afin d'interroger des base de données
relationnelles.

Les requêtes se présentent sous la forme \\({t|P(t)}\\), elle représente
l'ensemble des *n_uplets* tel que le prédicat \\(P(t)\\) est vrai pour \\(t\\).

\\(t\\) est une variable de *n_uplet* et \\(t[A]\\) représente la valeur de
l'attribut \\(A\\) dans \\(t\\). \\(t \in r\\) signifie que \\(t\\) est un 
*n_uplet* de \\(r\\).

Il existe aussi les connecteur logiques :
 * \\(\lor\\) : **ou** logique
 * \\((\land\\) : **et** logique 
 * \\(\neg\\) : la négation

Mais aussi des quantificateurs :
 * \\(\exists\\) : **il existe**, par exemple \\(\exists t \in r(Q(t))\\) il 
     existe un tuple t de r tel que Q est vrai.
 * \\(\forall\\) : **pour tout**, par exemple \\(\forall t \in r(Q(t))\\) - Q 
     est vrai pour tout tuple t de r.
 * \\(\nexists\\) : **il n'existe pas**, par exemple \\(\nexists t \in
     r(Q(t))\\) - il n'existe pas de tuple t dans r tel que Q est vrai.

### Un exemple concret : base de donnée cinéma

Essayons d'éclaicir tout celà à l'aide d'un exemple concret, considérons les
relations suivantes:

 * Films(titre, realisateur, Acteur) instance f
 * Programme(nom_cinemas, titre, horaire) instance p

#### les films réalisés par Terry Gilliam

\\( \\{ t | t \in f \land t[realisateur] = "\text{Terry Gilliam"} \\} \\)

#### les films ou jouent Jay et Silent Bob

\\( \\{ t | t \in f \land \exists s \in f( t[titre] = s[titre] \land 
t[acteur] = "Jay" \land s[acteur] = "Silent Bob" ) \\} \\)

#### tous les films programmés dans toutes les salles

\\( \\{ t | \exists s \in p(t[titre] = s[titre]) \\} \\)

#### Les films programmés à l'UGC mais pas au Megarama

\\( \\{ 
t | \exists s \in p(s[titre] = t[titre] 
\land s[\text{nom_cinemas}] = "UCG" 
\land {\neg} {\exists} u \in p( u[\text{nom_cinemas}] = "Megarama"
\land u[titre] = t[titre]
\\} \\)

#### Les titres des films qui sont passés à l'UGC et leurs réalisateurs

\\( \\{
t | \exists \in p(\exists u \in f((s[\text{nom_cinemas}] = "UGC"
\land s[titre] = u[titre] = t[titre]
\land t[realisateur] = u[realisateur]
\\} \\)

### Retour sur la notion de clé

comme nous lavons abordé précédement, une clé est nécessaire pour identifier des
*n_uplets* de façon unique sans pour autant en donner toutes leurs valeurs et
respecter leurs unicité.

Plus formellement

 * \\(X \text{ clé de } R(U) \textit{ avec } X \subseteq U \textit{ ssi } \forall 
     r:R(U) \\)
 * \\(\forall t_1, t_2 \in r \\)
 * \\(t_1\[X\] = t_2\[X\] \implies t_1 = t_2 \\)
 * \\(\neg \exists Y \subset X  \implies t_1[Y] = t_2[Y] \implies t_1 = t_2\\) 

### Expression saine

Il est possible d'écrire en calcul algébrique des requêtes qui retourne un
relation infinie. Un exemple parlant avec les numéros de comptes :

 * Soit \\(Numcompte(Num)\\)) avec l'instance \\(n\\)
 * Et la requête \\(\\{ t | \neg t \in n \\}\\) représentant les numéros de
     comptes non rencencés.
 * si on considère que \\( Dom(Num) = IN \\) alors la réponse à la question est
     infinie.

Un requête est saine si **quel que soit l'instance de la base** dans laquelle on
l'évalue, elle retourne **une réponse finie**.

## Calcul relationnel par domaine

Le calcul relationnel par domaine est un langage de requête non procédural. Il
ne fournit que la description de la requête et pas les méthodes pour la
résoudre. Elle prend la forme suivante:

\\(\\{ < x_1, x_2, ... , x_n> | P(x_1, x_2, ... , x_n)\\}\\)

 * \\(< x_1, x_2, ... , x_n>\\) représente les variables de domaine résultant
 * \\(P(x_1, x_2, ... , x_n)\\}\\) représente la formule similaire à ce que l'on
     trouve dans la logique des prédicats

Si on reprends notre exemple des cinémas, la requête permettant de trouver les
films proposé à l'UGC est

\\(\\{ \<t\> | \exists <nc, t, h> \in p(nc = "UGC"\\}\\)

## Relation entre les trois langages

Toute requête exprimée en algèbre peut être exprimée par le calcul et toute
requête saine du calcul peut être expriméeapt une requête de l'algèbre. Les
trois langages sont donc **équivalent d'un point de vue de la puissance
d'expression**.

L'algèbre est un langage procédural (quoi et comment) alors que le calcul ne
l'est pas (seulement quoi).
