Bonjour à tous,
Récemment, je me suis intéressé aux types de jointures suivants*: LEFT JOIN et RIGHT JOIN.
Je comprends que ces deux types de jointures, appliqués à deux ensembles de données qui partagent des éléments en communs, sont utilisés pour sélectionner les éléments qui appartiennent à un ensemble et pas à l’autre.
Mais je me pose la question suivante: pour quelle raison existe-t-il deux façons d’exprimer ce critère de sélection ?
D’une façon générale:
Est équivalent à:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SELECT ... FROM REFERENCE LEFT JOIN ATTRIBUT ON REFERENCE.key = ATTRIBUT.key
Et:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SELECT ... FROM ATTRIBUT RIGHT JOIN REFERENCE ON REFERENCE.key = ATTRIBUT.key
Est équivalent à:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT ... FROM REFERENCE LEFT JOIN ATTRIBUT ON REFERENCE.key = ATTRIBUT.key WHERE ATTRIBUT.key is NULL
Donc il est possible d’exprimer un même critère de sélection avec, au choix, l’un ou l’autre type de jointure (un LEFT JOIN ou un RIGHT JOIN).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT ... FROM ATTRIBUT RIGHT JOIN REFERENCE ON REFERENCE.key = ATTRIBUT.key WHERE ATTRIBUT.key is NULL
Dans ces conditions, y a-t-il un avantage à utiliser une forme plutôt qu’une autre ?
Exemple concret sous MySql :
Je vais donner un exemple concret pour bien illustrer mon propos.
Considérons deux tables, liées par une jointure.
Tous les citoyens, avec leur activité associée, même s'ils n'ont pas d'activité.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 SET foreign_key_checks = 0; DROP TABLE IF EXISTS citoyen; DROP TABLE IF EXISTS activite; SET foreign_key_checks = 1; CREATE TABLE activite ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255), PRIMARY KEY(id), CONSTRAINT uc_name UNIQUE (name) ) ENGINE=INNODB; INSERT INTO activite SET name='comptable'; SELECT LAST_INSERT_ID() INTO @comptable; INSERT INTO activite SET name='patissier'; SELECT LAST_INSERT_ID() INTO @patissier; INSERT INTO activite SET name='peintre'; SELECT LAST_INSERT_ID() INTO @peintre; INSERT INTO activite SET name='jardinier'; SELECT LAST_INSERT_ID() INTO @jardinier; INSERT INTO activite SET name='plombier'; SELECT LAST_INSERT_ID() INTO @plombier; INSERT INTO activite SET name='vitrier'; SELECT LAST_INSERT_ID() INTO @vitrier; INSERT INTO activite SET name='policier'; SELECT LAST_INSERT_ID() INTO @policier; INSERT INTO activite SET name='juge'; SELECT LAST_INSERT_ID() INTO @juge; INSERT INTO activite SET name='sabotier'; SELECT LAST_INSERT_ID() INTO @sabotier; CREATE TABLE citoyen ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255), fk_activite INT, PRIMARY KEY(id), FOREIGN KEY (fk_activite) REFERENCES activite(id), CONSTRAINT uc_name UNIQUE (name) ) ENGINE=INNODB; INSERT INTO citoyen SET name='Paul', fk_activite=@comptable; INSERT INTO citoyen SET name='Denis', fk_activite=@comptable; INSERT INTO citoyen SET name='Vincent', fk_activite=@patissier; INSERT INTO citoyen SET name='Eric', fk_activite=@peintre; INSERT INTO citoyen SET name='Laurent', fk_activite=@peintre; INSERT INTO citoyen SET name='Nicolas', fk_activite=@jardinier; INSERT INTO citoyen SET name='Valerie', fk_activite=@plombier; INSERT INTO citoyen SET name='Kathy', fk_activite=@vitrier; INSERT INTO citoyen SET name='Stephanie'; INSERT INTO citoyen SET name='Jean';
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SELECT citoyen.name, activite.name FROM citoyen LEFT JOIN activite ON citoyen.fk_activite = activite.id;
Toutes les activités, avec les citoyens associés, même pour les activités qui ne sont assurées par personne.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SELECT citoyen.name, activite.name FROM activite RIGHT JOIN citoyen ON citoyen.fk_activite = activite.id;
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SELECT activite.name, citoyen.name FROM activite LEFT JOIN citoyen ON citoyen.fk_activite = activite.id;
Tous les citoyens qui n'ont pas d'activité.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 SELECT activite.name, citoyen.name FROM citoyen RIGHT JOIN activite ON citoyen.fk_activite = activite.id;
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT citoyen.name, activite.name FROM citoyen LEFT JOIN activite ON citoyen.fk_activite = activite.id WHERE activite.id IS NULL;
Toutes les activités qui ne sont assurées par aucun citoyen.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT citoyen.name, activite.name FROM activite RIGHT JOIN citoyen ON citoyen.fk_activite = activite.id WHERE activite.id IS NULL;
ou
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT activite.name FROM activite LEFT JOIN citoyen ON citoyen.fk_activite = activite.id WHERE citoyen.id IS NULL;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 SELECT activite.name FROM citoyen RIGHT JOIN activite ON citoyen.fk_activite = activite.id WHERE citoyen.id is NULL;
Les 4 requêtes présentées peuvent être exprimées avec l’un ou l’autre type de jointure (LEFT JOIN ou RIGHT JOIN). Dans ces conditions, pourquoi a-t-on inventé deux façons d’exprimer la même chose?
Je pense que quelque chose m’échappe. Mais je ne vois pas ce que cela peut être.
Merci à tous,
Denis
Partager