Académique Documents
Professionnel Documents
Culture Documents
Attention : pour faciliter votre compréhension des di érents concepts, je vous conseille de lire ce tutoriel en entier et dans l'ordre proposé, vous
risqueriez sinon de rater certains enchaînements logiques.
Vous êtes informaticien dans une agence de presse et vous devez stocker les articles des journalistes de l'agence dans une base de
données relationnelle. Vous devez stocker pour chaque article son titre, son contenu et sa date, ainsi que le nom, le prénom et l'adresse e-
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
mail de l'auteur. Plusieurs journaux achètent des articles à l'agence de presse en question. Celle-ci voudrait savoir quels journaux ont
acheté quels articles. L'agence désire par ailleurs connaître, en plus de leur nom, l'adresse des journaux.
Règle n°1 : Regroupez dans une même table (= tableau de données) toutes les caractéristiques d'un élément.
Règle n°2 : Si une information se répète plusieurs fois dans une même table, il est préférable de créer une table dédiée à ce type d'information avec une
relation entre les deux tables.
Ces règles n'étant pas faciles à comprendre de prime abord, appliquons-les à notre exemple.
On aurait a priori tendance à créer une table "articles" ayant la structure suivante (notez l'absence de caractères spéciaux, d'espaces et d'accents dans les noms
des champs) :
articles
id_article
titre_article
nom_auteur
prenom_auteur
email_auteur
texte_article
date_article
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
id_article titre_article nom_auteur prenom_auteur email_auteur texte_article date_article
On remarque cependant qu’il y a répétition des informations sur l'auteur. En e et, un auteur peut avoir écrit plusieurs articles !
On va donc créer une table "auteurs" en relation avec la table "articles" pour éviter d'avoir une répétition inutile de toutes les informations sur les auteurs. Cela
permet en pratique, si vous voulez modifier un élément (par exemple l'adresse e-mail de l'auteur), de ne devoir le faire qu’une seule fois !
auteurs
id_auteur
nom_auteur
prenom_auteur
email_auteur
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
id_auteur nom_auteur prenom_auteur email_auteur
articles
id_article
titre_article
id_auteur
texte_article
date_article
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
id_article titre_article id_auteur texte_article date_article
On a donc créé une relation numérique entre deux tables pour éviter la répétition d'informations. On comprend l'importance du champ "id" de chaque table qui
doit absolument prendre une valeur di érente/unique pour chaque ligne de la table.
Le champ de type "id" (première colonne), qui contient un identifiant unique pour chaque élément (ligne) de la table, est appelé clé primaire (Primary Key = PK).
Dans la table articles, on a un autre type de champ "id", qui peut en e et prendre plusieurs fois la même valeur. C'est ce qu'on appelle une clé étrangère (Foreign
Key = FK). Il correspond à la clé primaire d'une autre table et permet de créer une relation avec celle-ci.
Dans notre cas, le champ (clé étrangère) "id_auteur" de la table articles correspond au champ (clé primaire) "id_auteur" de la table auteurs. On nomme
généralement de la même façon la clé primaire et la clé étrangère relative. La relation PK – FK est appelée relation 1 – N.
Règle n°3 : Il peut arriver que vous rencontriez une relation N – N, c'est-à-dire une relation où l'on a une répétition des éléments d'une table A dans une
autre table B, et également une répétition de plusieurs éléments de la table B dans la table A. Pour optimiser les tables et éviter ces répétitions, il faut dans
ce cas créer une table intermédiaire dans laquelle on stockera uniquement des "id".
Mise en pratique :
Reprenons notre exemple. En plus des tables articles et auteurs, créons la table "journaux".
journaux
id_journal
nom_journal
adresse_journal
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
id_journal nom_journal adresse_journal
1 Le Monde Paris
2 Le Figaro Paris
3 Le Soir Bruxelles
4 Libération Paris
On veut stocker les articles achetés par ces journaux à l'agence de presse. Un journal peut avoir acheté plusieurs articles, et un article peut avoir été acheté par
plusieurs journaux. On a donc une relation N – N.
Il ne nous est pas possible de stocker plusieurs articles pour un même journal (on a une seule ligne par journal dans la table journaux), il n'est pas non plus
possible de faire l'inverse (on ne peut pas stocker plusieurs journaux pour un même article, on a également une seule ligne par article dans la table articles). On
est donc obligés de créer une table intermédiaire pour stocker toutes nos relations (sous forme d'id). Grâce à ce subterfuge, on retrouve des relations 1 – N à la
place de la relation N – N.
Notre table stockant les relations pourrait ressembler à ceci (données aléatoires) :
jonction_articles_journaux
id_jonction_art_journ
id_article
id_journal
1 1 2
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
id_jonction_art_journ id_article id_journal
2 1 4
3 2 2
4 3 1
5 3 2
6 3 3
7 4 1
8 4 3
Règle n°4 : Il existe également la relation 1 – 1, qui résulte d'une erreur dans la conception de la base de données. Elle signifie en e et que chaque élément
d'une table A est en relation avec son équivalent dans la table B. Donc, l'élément d'id 1 de la table A est en relation directe avec l'élément d'id 1 de la table
B.
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
id_article titre_article id_auteur
1 blabla 26/01/2010
2 blibli 27/01/2010
3 bloblo 28/01/2010
4 blublu 28/01/2010
Il s'agit en fait d'une relation entre clés primaires (PK – PK). Chaque élément ayant sa correspondance dans l'autre table, on peut les regrouper dans une seule
table !
Pour terminer, voici la structure de la base de données, avec ses relations. Sous Microso Access, les relations 1 – N sont notées 1 –
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Notez que chaque champ de table a diverses propriétés, notamment un type (textuel, numérique, date, booléen, ...) ou une taille (nombre de caractères). Nous
n'aborderons pas ces détails ici.
Encore un truc inutile pour que mon code paraisse plus savant ?
Pas du tout !
Les jointures sont tout d'abord un moyen d'optimiser vos scripts, en améliorant leur vitesse d'exécution.
Pour le comprendre, reprenons l'exemple de l'agence de presse, et concentrons-nous sur la relation entre la table "articles" et la table "auteurs". Nous avons donc
une relation entre les deux tables via le champ "id_auteur".
Dans notre script, nous désirons a icher une liste des articles avec, en plus du titre de l'article, le nom de l'auteur.
<?
$req_articles = mysql_query('SELECT `titre_article`,`id_auteur` FROM `articles` ');
while ($data_articles = mysql_fetch_array($req_articles))
{
$req_auteurs = mysql_query('SELECT `nom_auteur` FROM `auteurs` WHERE `id_auteur` = "'.$data_articles['id_auteur'].'" ');
$data_auteurs = mysql_fetch_array($req_auteurs);
Bref, il sélectionne l'id de l'auteur dans la table "articles", puis l'utilise dans une seconde requête sql qui cherche l'auteur correspondant dans la table "auteurs".
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Mettre une requête sql dans une boucle est une très mauvaise idée, cela réduit (de manière plus ou moins importante selon la requête) les performances
de votre script !
Grâce aux jointures, vous apprendrez à sélectionner toutes les informations dont vous avez besoin en une seule requête !
Par ailleurs, comme vous pourrez le découvrir à la lecture de ce tutoriel, les jointures o rent un confort et une puissance bien utiles lorsque vos scripts se
complexifient.
Dans ce tutoriel, par soucis de simplification, nous sélectionnerons souvent tous les champs (en faisant un SELECT * ) dans les requêtes exemples. En
pratique, il est conseillé de ne sélectionner que les champs dont vous avez besoin (afin de ne pas alourdir inutilement votre sélection).
Ancienne syntaxe
Requêtes multi-tables
Considérons un exemple simplifié : nous avons 2 tables "clients" et "commandes".
Structure :
clients
id_client
nom_client
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
commandes
id_commande
id_client
date_commande
Nous avons conçu notre base de données avec une relation 1 - N entre les 2 tables (via le champ "id_client"). Les clients peuvent en e et avoir passé plusieurs
commandes.
Données :
id_client nom_client
1 Jacques Dupont
2 Marcel Dubois
3 Nathalie Leroy
4 Marc Degraux
5 Julie Duchemin
1 4 26/01/2010
2 1 26/01/2010
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
id_commande id_client date_commande
3 1 28/01/2010
4 3 28/01/2010
5 4 28/01/2010
6 3 29/01/2010
7 5 29/01/2010
8 4 30/01/2010
9 1 01/02/2010
10 4 01/02/2010
11 5 01/02/2010
12 3 01/02/2010
N'essayez pas de chercher une logique dans les id_client, ceci est un exemple aléatoire, chaque client peut commander à n'importe quel moment (et même
plusieurs fois le même jour). On notera que jusqu'à présent Marcel Dubois (id_client = 2) n'a pas passé de commande.
E ectuons maintenant une requête multi-tables, en l'occurence la sélection des données de nos 2 tables en même temps (on va donc joindre nos 2 tables).
Vu que nous n'avons pas spécifié de critère de jointure dans notre requête (c'est-à-dire la manière dont on doit joindre les 2 tables), nous obtenons comme
résultat l'ensemble des relations/combinaisons possibles entre les deux tables.
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Ainsi, chaque ligne de la table "clients" est associée à chaque ligne de la table "commandes". En tout dans notre exemple on obtient donc comme résultat 60
lignes (5 lignes de la table clients multipliées par 12 lignes de la table commandes) qui sont les 60 relations/combinaisons possibles entre les lignes de nos 2
tables.
En données cela donne :
Utilisation du WHERE
Heureusement notre exemple comporte peu de données. Mais si vous travaillez avec beaucoup de données, l'absence de critère de jointure peut faire sou rir
votre serveur pour, au final, vous retrouver avec un résultat peu utile. Nous allons voir comment définir un critère de jointure.
Un des critères de jointure auquel on pense est évidemment la relation que nous avons définie entre nos deux tables lors de la conception de la base de données,
à savoir la relation via le champ "id_client".
Notre requête SQL avec critère de jointure se construit comme suit :
Etant donné qu'il existe 2 champs portant un même nom (id_client) dans notre requête, il est obligatoire de spécifier leur table respective (en indiquant le
nom de celle-ci suivi d'un point avant le nom du champ).
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
On a e ectué ce qu'on appelle une jointure interne entre nos deux tables.
On constate qu'il ne reste que 12 lignes sur 60 une fois qu'on a introduit notre critère de jointure.
Notons notamment la disparition des lignes contenant "Marcel Dubois" (id_client = 2). Cela s'explique par le fait que Marcel Dubois n'a passé aucune commande,
il n'est donc pas présent dans la table commandes.
La jointure interne a pour particularité de n'a icher que les lignes qui respectent le critère de jointure ; il est donc possible qu'une ligne de la table "clients"
qui n'a de relation avec aucune ligne de la table "commandes" ne soit pas du tout a ichée dans le résultat de la requête (comme c'est le cas dans notre
exemple avec l'id_client 2, Marcel Dubois) !
Nous verrons dans la section suivante (jointures externes) qu'il est néanmoins possible d'a icher malgré tout ces lignes sans relations.
Nouvelle syntaxe
Afin d'améliorer la lisibilité des requêtes (notamment bien séparer ce qui relève du filtrage et ce qui relève de la jointure), et dans une certaine mesure de les
optimiser, une nouvelle syntaxe a été introduite pour les jointures.
Notre requête :
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
SELECT *
FROM `clients`,`commandes`
WHERE `clients`.`id_client` = `commandes`.`id_client`
SELECT *
FROM `clients`
INNER JOIN `commandes`
ON `clients`.`id_client` = `commandes`.`id_client`
Bref, il n'y a plus qu'une seule table dans le FROM, et pour chaque table que l'on désire joindre on doit utiliser INNER JOIN suivi du nom de la table, puis ON suivi
du critère de jointure.
A noter que le terme INNER est facultatif, on peut simplement écrire JOIN.
Les critères de sélection WHERE, LIMIT et ORDER BY se placent après les jointures !
SELECT *
FROM `clients`
JOIN `commandes`
ON `clients`.`id_client` = `commandes`.`id_client`
JOIN `produits`
ON `commandes`.`id_commande` = `produits`.`id_commande`
WHERE `clients`.`code_postal` = "75000"
ORDER BY `commandes`.`date_commande` ASC
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Les jointures externes
Les jointures externes sont plus "complètes" que les jointures internes. En plus de sélectionner l'ensemble des lignes des 2 tables respectant le critère de
jointure comme le font les jointures internes, elles sélectionnent les données d'une des tables qui ne respectent pas le critère de jointure.
LEFT JOIN
Exemple :
SELECT *
FROM TableGauche
LEFT JOIN TableDroite
ON critère de jointure
Le LEFT JOIN (ou LEFT OUTER JOIN) implique que l'on sélectionne toutes les lignes respectant le critère de jointure, puis on ajoute toutes les lignes de la table
"TableGauche" qui ont été rejetées car elles ne respectaient pas le critère de jointure.
Appliquons le LEFT JOIN à l'exemple utilisé pour les jointures internes :
SELECT *
FROM `clients`
LEFT JOIN `commandes`
ON `clients`.`id_client` = `commandes`.`id_client`
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Bref, on a le même résultat qu'avec INNER JOIN, auquel on a juste ajouté les éléments de la table de gauche (en l'occurence "clients") qui ne respectaient pas le
critère de jointure.
On voit donc réapparaître Marcel Dubois (id_client = 2) qui n'avait passé aucune commande, et n'était donc pas présent dans la table "commandes", et ne
respectait donc pas au moins une fois le critère de jointure (ce qui l'avait exclu des résultats de la jointure interne).
La clause USING(liste_champs) permet de définir les champs communs à prendre en considération (critère de jointure).
Exemple :
SELECT *
FROM `tablea`
LEFT JOIN `tableb`
USING (`champ1`,`champ2`,`champ3`)
est équivalent à :
SELECT *
FROM `tablea`
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
LEFT JOIN `tableb`
ON `tablea`.`champ1` = `tableb`.`champ1` AND `tablea`.`champ2` = `tableb`.`champ2` AND `tablea`.`champ3`= `tableb`.`champ3`
RIGHT JOIN
Le RIGHT JOIN (ou RIGHT OUTER JOIN) implique que l'on sélectionne toutes les lignes respectant le critère de jointure, puis on ajoute toutes les lignes de la table
"TableDroite" qui ont été rejetées car elles ne respectaient pas le critère de jointure.
FULL JOIN
Le FULL JOIN (ou FULL OUTER JOIN) implique que l'on sélectionne toutes les lignes respectant le critère de jointure, puis on ajoute toutes les lignes de la table
"TableGauche" et de la table "TableDroite" qui ont été rejetées car elles ne respectaient pas le critère de jointure.
A noter que le FULL JOIN n'existe pour le moment pas sous MySQL.
Restons lisibles !
Les Alias
Pour comprendre l'utilité des alias, prenons une requête multi-tables :
SELECT *
FROM `clients`,`commandes`
WHERE `clients`.`id_client` = `commandes`.`id_client`
Cette requête-ci est facile à lire. Cependant, certaines requêtes peuvent vite devenir assez longues lorsque l'on travaille avec plus de deux tables. Pour améliorer
la lisibilité de la requête, il existe ce qu'on appelle les alias, qui sont des surnoms que l'on donne aux tables.
A noter qu'une fois un alias attribué à une table on peut toujours utiliser son nom complet, les deux fonctionnent.
Pour attribuer un alias à une table, il su it simplement de l'ajouter dans le FROM juste après le nom de la table (avec un espace entre le nom complet de la table et
son alias). Le but étant d'alléger le code, les alias comptent généralement peu de caractères.
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
SELECT *
FROM `clients` CL,`commandes` COM
WHERE CL.`id_client` = COM.`id_client`
SELECT *
FROM `clients` CL
JOIN `commandes` COM
ON CL.`id_client` = COM.`id_client`
Si l'alias n'est qu'un outil pour améliorer la lisibilité de la requête dans le cas des tables, il est par contre essentiel dans le cas des champs.
Dans les requêtes multi-tables, il peut arriver que deux champs de tables di érentes portent le même nom. Cela ne pose pas de problème dans la requête elle-
même étant donné que l'on précise à chaque fois la table à laquelle appartient le champ, mais cela peut par contre être problématique dans l'exploitation PHP du
résultat de la requête.
Exemple :
SELECT A.`quantite`,B.`quantite`
FROM `tablea` A, `tableb` B
Dans cet exemple, nous avons 2 tables ("tablea" et "tableb") qui contiennent deux champs portant le même nom ("quantite").
Lorsque nous utilisons notre habituel mysql_fetch_array (ou mysql_fetch_object) pour récupérer les données issues de la requête, nous ne sommes pas en
mesure (sans diminuer la lisibilité du code) de di érentier les 2 champs.
Ainsi, pour faire appel au champ "quantite" de la table "tableb", on utilisera désormais son alias :
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
<?
$req = mysql_query('SELECT A.`quantite`,B.`quantite` AS `quantite_bis` FROM `tablea` A, `tableb` B');
while ($data = mysql_fetch_array($req))
{
echo $data['quantite']; //affiche le contenu du champ "quantite" de la table "tablea"
Conditions de jointure
Dans les conditions de jointure on peut utiliser une égalité, mais également d'autres opérateurs de comparaison :
Opérateur Signification
> supérieur
< inférieur
<> di érent de
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
Opérateur Signification
IN dans un ensemble
Source
La jointure croisée
La jointure croisée est simplement la nouvelle syntaxe pour les requêtes multi-tables sans critère de sélection WHERE que nous avons abordées au tout début de
la partie sur les jointures internes.
devient :
La jointure naturelle
Elle permet d'éviter de devoir spécifier le critère de jointure. Le compilateur SQL se charge de rechercher dans les 2 tables les champs qui ont un nom identique.
SELECT *
FROM `clients`
NATURAL JOIN `commandes`
équivaut donc à :
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD
SELECT *
FROM `clients`
JOIN `commandes`
ON `clients`.`id_client` = `commandes`.`id_client`
A noter que NATURAL JOIN est une jointure naturelle interne. Vous pouvez également faire une jointure naturelle externe NATURAL LEFT JOIN ou NATURAL
RIGHT JOIN !
Auto-jointures
Il est possible de joindre une table à elle-même. Pour ce faire, il conviendra d'utiliser les alias.
Exemple :
SELECT *
FROM `tablea` T1
JOIN `tablea` T2
ON T1.champ = T2.champ
Quelques références
http://dev.mysql.com/doc/refman/5.0/en/join.html
http://sqlpro.developpez.com/cours/sqlaz/jointures/
http://mhubiche.developpez.com/Access/tutoJointures/
Voilà, j'espère que ce tutoriel vous sera utile et vous a donné envie d'en savoir plus sur les jointures. De tout ceci, retenez une chose : exploitez un maximum les
possibilités o ertes par SQL avant d'avoir recours à PHP, cela rendra vos scripts d'autant plus e icaces. Je vous invite d'ailleurs à lire les autres tutoriels SQL
présents sur le Site du Zéro ! ;)
Create PDF in your applications with the Pdfcrowd HTML to PDF API PDFCROWD