Notre but est de faciliter la compréhension de l'utilisation des bases
de données relationnelles : nous gommerons donc volontairement tous
les aspects trop théoriques tout en étant conscient que ceux-ci sont
nécessaires à une connaissance en profondeur des mécanismes
sous-jacents des bases de données relationnelles.
Notamment, toute la partie de l'analyse conceptuelle des données et des traitements, l'étude des dépendances fonctionnelles, sera passée sous silence (ce qui est un scandale, j'en conviens...). Nous ne pourrons, par contre, pas échapper, à quelques rudiments d'algèbre relationnelle : j'essaierai de les faire passer le plus simplement possible...
Oracle et Informix dominent le marché actuel, SQL-Server (de
Microsoft) tente de s'imposer dans le monde des PC sous NT. À côté des
ces produits, très chers, existent heureusement des systèmes libres et
gratuits : MSQL, MYSQL et POSTGRESQL sont
les plus connus. Ils existent évidemment sous forme de paquetages rpm
ou deb pour Linux et leurs sources peuvent se compiler sur quasiment
tous les Unix.
Bien que ces SGBDR n'aient pas la puissance des produits commerciaux,
certains s'en approchent de plus en plus : c'est le cas de
POSTGRESQL, notamment, que nous avions présenté dans des
numéros précédents de Linux Magazine. Les différences notables
concernent principalement les environnements de développement qui sont
de véritables ateliers logiciels sous Oracle et qui sont réduits à des
interfaces de programmation C, Python, Perl sous
POSTGRESQL. Il en va de même pour les interfaces utilisateurs
: il en existe pour POSTGRESQL, mais ils n'ont certainement
pas la puissance de leurs équivalents commerciaux.
Ces limites ne nous gèneront pas car, pour apprendre SQL, pas besoin de clickodrome ! D'autre part, si la dernière version de POSTGRESQL utilise encore un sous-ensemble de SQL-4, celui-ci dispose de toutes les fonctionnalités essentielles. Le jour où vous ressentirez les limites de ce sous-ensemble, vous vous rappelerez avec émotion de ce petit article ;-)
Vouloir traiter de SQL sans présenter l'algèbre relationnelle serait comme enseigner un langage de programmation sans présenter l'algorithmique. Nous consacrerons donc un peu de temps à étudier le modèle défini par Codd, et dont SQL n'est que la traduction informatique.
Soit la relation ETUDIANTS, représentant un ensemble d'étudiants. Celle-ci sera représentée par le tableau suivant :
Num_Etudiant | Nom | Prenom | Date_Naissance | Code_Diplome | Adresse | Code Postal | Ville | Tel |
... | ... | ... | ... | ... | ... | ... | ... | ... |
9901 | Martin | Olivier | 10/10/1979 | A | 10, Route de Toulouse | 31130 | Balma | 05.61.12.13.14 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
9945 | Dupont | Catherine | 09/09/1980 | B | 2, Av. de Paris | 31000 | Toulouse | |
... | ... | ... | ... | ... | ... | ... | ... | ... |
Cette relation sera notée :
ETUDIANTS(Num_Etudiant, Nom, Prenom, Date_Naissance, Code_Diplome, Adresse, Code Postal, Ville, Tel)
Sa clé est l'attribut Num_Etudiant, car chaque étudiant peut être désigné de manière unique par ce seul attribut. Le problème de la détermination de la clé primaire d'une relation est un sujet qui nous amènerait trop loin pour être abordé ici. Le lecteur intéressé se reportera aux ouvrages cités en fin d'article.
Pour être exploitable, une relation doit être normalisée. Plusieurs formes normales ont été définies et nous nous bornerons à utiliser des relations en troisième forme normale (3FN). Vous trouverez dans les différents ouvrages des références à une 3FNBCK (troisième forme normale de Boyce-Codd-Kent), et à une 4FN (multivaluée) : elles ne seront pas utilisées ici.
Une relation est en 1FN si elle possède une clé, que tous ses attributs dépendent fonctionnellement de cette clé et sont atomiques (non décomposables) : c'est pour cette raison que nous découpons l'adresse en ses différentes parties (adresse, code postal et ville), au lieu de la considérer comme un seul attribut.
Une relation est en 2FN si elle est en 1FN et que tous les attributs
non clé dépendent pleinement de la clé (on ne peut trouver un
sous-ensemble d'attributs de la clé qui suffirait à identifier de
façon unique un autre attribut). Si la clé est réduite à un attribut
(comme dans notre relation ETUDIANT, le problème est
trivial).
Soit, par exemple, la relation COMMANDE suivante :
COMMANDE(Numero_Cde, Code_Article, Date_Cde, Nom_Fournisseur, Adr_Fournisseur, Cp_Fournisseur, Ville_Fournisseur)
Cette relation est en 1FN car tous ses attributs sont simples. Elle
n'est pas en 2FN car l'attribut Nom_Four ne dépend que d'une
partie de la clé (la connaissance de Numero_Cde suffit à
déterminer le fournisseur).
Lorsqu'une relation n'est pas en 2FN, il y a donc un problème de
redondance des données dans la base : ici, par exemple, il faudrait
répéter les champs Date_Cde,
Nom_Fournisseur, Adr_Fournisseur,
Cp_Fournisseur, Ville_Fournisseur pour chaque
article de la commande (alors que c'est le même...).
Afin de mettre cette relation en 2FN, il suffit de la décomposer selon les attributs qui introduisent la redondance (ici, Code_Article) :
COMMANDE(Numero_Cde, Date_Cde, Nom_Fournisseur, Adr_Fournisseur, Cp_Fournisseur, Ville_Fournisseur)
ART_CDE(Numero_Cde, Code_Article)
Cette décomposition est sans perte d'information, et l'on constate que
les problèmes de redondance précédents ont disparu.
Les deux relations obtenues ici sont nécessairement en 2FN : COMMANDE a une clé réduite à un attribut (il ne peut donc exister de sous-ensemble...) et les deux uniques attributs de ART_CDE forment la clé.
Une relation est en 3FN si elle est en 2FN et si tout attribut
n'appartenant pas à la clé ne dépend pas aussi d'un attribut non clé. Il n'y
a donc pas de transitivité dans les dépendances entre les attributs.
Reprenons la relation COMMANDE obtenue à l'étape précédente :
elle est bien en 2FN, mais pas en 3FN : les attributs
Adr_Fournisseur, Cp_Fournisseur et
Ville_Fournisseur dépendent aussi (et surtout) de
l'attribut Nom_Fournisseur.
On a donc une transitivité dans les dépendances :
Cette transitivité induit, elle aussi, des problèmes de redondances,
ainsi que des problèmes de mises à jour de la base de données : les
caractéristiques d'un même fournisseur sont répétées à chaque fois
qu'une commande le concerne et, si un
fournisseur change d'adresse, il faudra modifier tous les tuples de la
relation où celui-ci apparaît.
Là encore, la solution consiste à décomposer la relation selon l'attribut qui introduit la transitivité. COMMANDE devient donc :
COMMANDE(Numero_Cde, Date_Cde, Nom_Fournisseur)
FOURNISS(Nom_Four, Adr_Four, Cp_Four, Ville_Four)
Nous n'avons pas perdu d'informations et les problèmes de redondance
et de mise à jour sont maintenant réglés.
Les deux relations obtenues, ainsi que la relation ART_CDE, sont en 3FN : nous avons donc désormais un schéma en troisième forme normale et nous nous en contenterons.
Maintenant que nous avons défini notre univers : l'ensemble des
relations, voyons les opérations qu'il est possible d'effectuer.
L'algèbre de Codd repose sur la théorie des ensembles et, sur les neuf opérateurs principaux, quatre sont les opérateurs ensemblistes bien connus : union, intersection, différence et produit cartésien. Les cinq autres sont propres aux tableaux : projection, sélection, différence, jointure et division. Nous verrons que le langage SQL n'est rien d'autre que la représentation, dans un langage informatique, de ces opérations.
Trois de ces opérateurs agissent sur deux relations de même schéma, ce sont l'union, l'intersection et la différence.
L'opérateur de produit cartésien agit sur des relations ayant des schémas différents :
Les opérateurs suivants agissent sur une relation :
Les deux autres opérateurs agissent sur deux relations n'ayant pas nécessairement le même schéma :
Soit les schémas de relation suivants :
COMMANDE(Num_Cde, Date_Cde, Num_Four, Montant_Cde)
FOURNISSEUR(Num_Four, Nom_Four, Adr_Four, ...)
Soient les questions suivantes :
Cela peut se résumer par l'expression relationnelle suivante :
Union(Selection(COMMANDE ; Date_Cde = '1998'), Selection(COMMANDE ; Date_Cde = '1999'))
Cette question peut être traitée à l'aide de deux sélections, suivies d'une intersection :
Intersection(Selection(COMMANDE ; Date_Cde = '1998'), Selection(COMMANDE ; Num_Four = 'CD82'))
Ou, plus simplement à l'aide d'une sélection portant sur les deux critères :
Selection(COMMANDE ; Date_Cde = '1998' ET Num_Four = 'CD82'),
Projection(FOURNISSEUR ; Nom_Four, Ville_Four)
Selection(Projection(FOURNISSEUR ; Nom_Four, Ville_Four) ; Ville_Four = 'Toulouse')
R1 = Selection(FOURNISSEUR ; Nom_Four = 'Mercier S.A.') R2 = Jointure(COMMANDE, R1 ; COMMANDE.Num_Four = R1.Num_Four) R3 = Projection(R2 ; Num_Cde, Date_Cde)
Nous avons ici séparé chaque étape pour faciliter la compréhension.
R1 = Selection(COMMANDE ; Num_Four = 'CD82') R2 = Difference(COMMANDE, R1) R3 = Projection(R2 ; Num_Cde, Date_Cde)
LIGNE_CDE(Num_Cde, Code_Art)
ARTICLE(Code_Art, Des_Art, Prix)
La réponse à la question « Quelles sont les commandes contenant tous les articles ? » est :
Selection(Division(LIGNE_CDE, ARTICLE) ; Num_Cde)
Quoi ? L'article est fini et l'on n'a pas vu une seule instruction SQL ? Non, c'est vrai, mais nous avons posé (d'une façon très rudimentaire) les bases des prochains articles qui, eux, présenteront le langage et créeront des bases de données permettant de tester réellement les requêtes.
En attendant, vous pouvez ronger votre frein en consultant les ouvrages suivants :
Cette liste est loin d'être exhaustive, mais ce sont les ouvrages que
j'utilise... Vous trouverez dans ceux-ci d'autres références,
françaises et internationales.
Une recherche utilisant le mot clé « SQL » sur yahoo! devrait également vous proposer un certain nombre de documents, voire de cours complets, disponibles en téléchargement.
This document was generated using the LaTeX2HTML translator Version 98.1p1 release (March 2nd, 1998)
Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
The command line arguments were:
latex2html -split 0 sql1.
The translation was initiated by Eric Jacoboni on 1999-09-27