IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

LEFT JOIN ou RIGHT JOIN : Interchangeables ?


Sujet :

Langage SQL

  1. #1
    Membre régulier
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Points : 114
    Points
    114
    Par défaut LEFT JOIN ou RIGHT JOIN : Interchangeables ?
    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:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            SELECT     ...
            FROM       REFERENCE
            LEFT JOIN  ATTRIBUT ON REFERENCE.key = ATTRIBUT.key
    Est équivalent à:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            SELECT     ...
            FROM       ATTRIBUT
            RIGHT JOIN REFERENCE ON REFERENCE.key = ATTRIBUT.key
    Et:

    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
    Est équivalent à:

    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
    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).

    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.

    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';
    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
        SELECT      citoyen.name, activite.name
        FROM        citoyen
        LEFT JOIN   activite ON citoyen.fk_activite = activite.id;
    ou

    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;
    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      activite.name, citoyen.name
        FROM        activite
        LEFT 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        citoyen
        RIGHT JOIN  activite 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
    4
        SELECT      citoyen.name, activite.name
        FROM        citoyen
        LEFT JOIN   activite 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      citoyen.name, activite.name
        FROM        activite
        RIGHT JOIN  citoyen 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      activite.name
        FROM        activite
        LEFT JOIN   citoyen ON citoyen.fk_activite = activite.id
        WHERE       citoyen.id IS NULL;
    ou

    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

  2. #2
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 193
    Points : 28 077
    Points
    28 077
    Par défaut
    Citation Envoyé par WinNew Voir le message
    ...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....
    Déjà, en commençant par là, tu as tout faux, ce n'est pas du tout ça.

    LEFT JOIN --> Tous les éléments de la table de gauche avec éventuellement pour chaque élément, les éléments de la table de droite correspondants, s'il y a correspondance
    RIGHT JOIN --> Tous les éléments de la table de droite avec éventuellement pour chaque élément, les éléments de la table de gauche correspondants, s'il y a correspondance

    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:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            SELECT     ...
            FROM       REFERENCE
            LEFT JOIN  ATTRIBUT ON REFERENCE.key = ATTRIBUT.key
    Est équivalent à:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
            SELECT     ...
            FROM       ATTRIBUT
            RIGHT JOIN REFERENCE ON REFERENCE.key = ATTRIBUT.key
    Dans ce cas bien précis, avec une seule jointure, effectivement les résultats devraient identiques. Mais les requêtes sont rarement aussi simplistes.

    Imagine une requete avec une dizaine ou une quinzaine de jointures qui partent dans tous les sens, a partir de la table principale, mais aussi des tables jointes. Tu dois imaginer ta requete comme étant un arbre, la 1er table (celle du From) étant le tronc, les autres étant les branches.
    Si tu part avec la table Attributs comme tronc, tu n'auras pas les mêmes résultats que si tu part de la table Référence, car ton référentiel ne sera pas le même. Le cas que tu donne étant un cas particulier de ce schéma.
    --- Sevyc64 ---

    Parce que le partage est notre force, la connaissance sera notre victoire

  3. #3
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sevyc64 Voir le message
    Dans ce cas bien précis, avec une seule jointure, effectivement les résultats devraient identiques. Mais les requêtes sont rarement aussi simplistes.

    Imagine une requete avec une dizaine ou une quinzaine de jointures qui partent dans tous les sens, a partir de la table principale, mais aussi des tables jointes. Tu dois imaginer ta requete comme étant un arbre, la 1er table (celle du From) étant le tronc, les autres étant les branches.
    Si tu part avec la table Attributs comme tronc, tu n'auras pas les mêmes résultats que si tu part de la table Référence, car ton référentiel ne sera pas le même. Le cas que tu donne étant un cas particulier de ce schéma.
    Quand on part du bon point de départ, en suivant la règle "en prendre le moins possible le plus tôt possible", on n'a jamais besoin du RIGHT JOIN (ou presque). En 13 ans d'expérience, où j'écrit quotidiennement des requêtes, j'ai dû me servir 2 ou 3 fois de RIGHT JOIN. A vrai dire, autant que de fois où je me suis servi de FULL JOIN, c'est à dire vraiment très rarement.
    On ne jouit bien que de ce qu’on partage.

  4. #4
    Membre régulier
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Points : 114
    Points
    114
    Par défaut
    @sevyc64

    Bonjour Yves,

    Merci pour ta réponse. J'ai l'habitude de me représenter les choses visuellement. Je vais essayer de formaliser graphiquement une jointure par un arbre.

    Quand j'aurais trouvé une manière claire de formaliser ces notions, je vais l'exposer sur le forum.

    Cordialement,

    Denis

  5. #5
    Membre régulier
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Points : 114
    Points
    114
    Par défaut
    @StringBuilder

    Bonjour,

    Je te remercie pour ton intervention. Si je comprends bien le choix de la "formule" (LEFT JOIN ou RIGHT JOIN) la plus appropriée dépend aussi des tailles respectives des ensembles de données à manipuler.

    Cordialement,

    Denis

  6. #6
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Non pas d'histoire de volumétrie.
    Les syntaxes LEFT OUTER JOIN et RIGHT OUTER JOIN sont similaires mais s'appliquent comme vous l'avez compris en fonction de l'ordre de ce qu'on lui donne.

    J'imagine que les deux ont été créé pour laisser plus de souplesse aux développeurs, maintenant d'expérience je vous conseille d'en choisir un et de n'utiliser que celui là, quand on retrouve des LEFT et RIGHT dans la même requête ça peut devenir difficile à relire.

    LEFT JOIN possède un avantage certain : il se lit naturellement, de haut en bas et de gauche à droite.

  7. #7
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par WinNew Voir le message
    Si je comprends bien le choix de la "formule" (LEFT JOIN ou RIGHT JOIN) la plus appropriée dépend aussi des tailles respectives des ensembles de données à manipuler.
    Non en effet, il n'y a pas de notion de volumétrie.

    En revanche, un adage SQL, c'est de filtrer au maximum le plus tôt possible.

    Hors, autant le LEFT JOIN se traduit littéralement "pour ma table a, ramène toutes les lignes de la table b, sinon null"
    => Je ne rajoute pas de lignes dans mon résultat, je respecte donc l'adage

    Alors que le RIGHT JOIN se traduit littéralement "pour la table a, ramène toutes les lignes qui ont un lien vers b, et complète avec des nulls pour les lignes de b qui n'ont pas de lien avec a"
    => Clairement, on va rajouter des lignes dans le résultat. On préférera donc filtrer sur B avant A.

    Enfin, c'est mon interprétation personnelle.
    On ne jouit bien que de ce qu’on partage.

  8. #8
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    En revanche, un adage SQL, c'est de filtrer au maximum le plus tôt possible.

    Hors, autant le LEFT JOIN se traduit littéralement "pour ma table a, ramène toutes les lignes de la table b, sinon null"
    => Je ne rajoute pas de lignes dans mon résultat, je respecte donc l'adage

    Alors que le RIGHT JOIN se traduit littéralement "pour la table a, ramène toutes les lignes qui ont un lien vers b, et complète avec des nulls pour les lignes de b qui n'ont pas de lien avec a"
    => Clairement, on va rajouter des lignes dans le résultat. On préférera donc filtrer sur B avant A.
    J'aime bien ton adage dans sa philosophie mais je ne pense pas que ça change grand chose réellement dans le SGBD d'utiliser LEFT ou RIGHT, au niveau des performances.
    Il est même possible qu'un optimiseur performant récrive logiquement la requête dans le sens le plus approprié.

    Je te rejoins aussi sur la rareté de l'emploi du RIGHT par rapport à l'écrasante majorité du LEFT. N'y voyez aucune connotation politique de ma part en ces temps électoraux ! En ce domaine, le résultat est bien moins certain !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  9. #9
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 193
    Points : 28 077
    Points
    28 077
    Par défaut
    Citation Envoyé par WinNew Voir le message
    J'ai l'habitude de me représenter les choses visuellement. Je vais essayer de formaliser graphiquement une jointure par un arbre.
    Non pas une, mais un certain nombre de jointures.
    Avec une seule jointure, tu as un tronc et une branche dans l'alignement du tronc, ça ne visualise pas grand chose. Par contre avec un certain nombre de jointures (et de "sous-jointures", de "sous-sous-jointures", etc) ça devient intéressant.


    Attention aussi à une faute courante, même les pros la font et ne comprennent pas toujours d’où vient leur bug, sur une jointure externe (Left ou Right), de mettre dans la clause WHERE une condition sur la table jointe sans tenir compte des valeurs nulles revient à faire une jointure interne (INNER JOIN) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM A LEFT JOIN B ON A.FK=B.PK WHERE B.Champ=Valeur
    n'est plus une jointure gauche mais est équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM A INNER JOIN B ON A.FK=B.PK WHERE B.Champ=Valeur
    Pour que ça reste une jointure gauche il faut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM A LEFT JOIN B ON A.FK=B.PK WHERE B.Champ IS NULL OR B.Champ=Valeur
    --- Sevyc64 ---

    Parce que le partage est notre force, la connaissance sera notre victoire

  10. #10
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Représenter visuellement des jointures ?
    Faire un MCD de la BDD !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  11. #11
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 080
    Points : 30 801
    Points
    30 801
    Par défaut
    Citation Envoyé par sevyc64 Voir le message
    Pour que ça reste une jointure gauche il faut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM A LEFT JOIN B ON A.FK=B.PK WHERE B.Champ IS NULL OR B.Champ=Valeur
    De cette manière, on sélectionne aussi les lignes de la table B où B.Champ est null, ce qui n'est pas le but recherché

    Il vaut mieux écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT  *
    FROM    A
        LEFT JOIN 
            B 
            ON  A.FK      = B.PK 
            AND B.Colonne = Valeur
    Ce qui met bien en évidence la restriction opérée sur la table B avant jointure
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  12. #12
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Oui c'est ce que j'explique dans mon article de blog.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  13. #13
    Membre régulier
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Points : 114
    Points
    114
    Par défaut
    Bonjour à tous,

    Je crois que j'ai finalement compris ces deux types de jointures.

    Supposons que l'on a trois tables "A", "B" et "C".
    • "A" est liée à "B" par une jointure. A <-> B
    • "A" est liée à "C" par une jointure. A <-> C


    Sur chaque illustration, la "table de référence" pour la jointure est de couleur rouge pâle.

    D'une façon générale:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        SELECT      ...
        FROM        table_de_référence
        LEFT JOIN   autre_table ON ...;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        SELECT      ...
        FROM        autre_table
        RIGHT JOIN  table_de_référence ON ...;
    LEFT JOIN

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        SELECT      ...
        FROM        A
        LEFT JOIN   B ON A.key.B.key;


    RIGHT LOIN

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        SELECT      ...
        FROM        A
        RIGHT JOIN  B ON A.key.B.key;


    Combinaison d'un LEFT JOIN et d'un RIGHT JOIN

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        SELECT      ...
        FROM        A
        LEFT JOIN   B ON A.key = B.key
        RIGHT JOIN  C ON A.key = C.key;
    Il faut évaluer les jointures dans l'ordre de déclaration de ces dernières. Dans cet exemple, on effectue d'abord le LEFT JOIN. Puis on effectue le RIGHT JOIN sur le résultat obtenu précédemment.



    Voili, voilou,

    Vous confirmez?

    Cordialement,

    Denis

  14. #14
    Modérateur
    Avatar de sevyc64
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2007
    Messages
    10 193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 193
    Points : 28 077
    Points
    28 077
    Par défaut
    Citation Envoyé par al1_24 Voir le message
    De cette manière, on sélectionne aussi les lignes de la table B où B.Champ est null, ce qui n'est pas le but recherché
    Dans le cas ou un enregistrement B serait bien retourné mais avec le champ en question nul, effectivement.

    Citation Envoyé par al1_24 Voir le message
    Il vaut mieux écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT  *
    FROM    A
        LEFT JOIN 
            B 
            ON  A.FK      = B.PK 
            AND B.Colonne = Valeur
    Ce qui met bien en évidence la restriction opérée sur la table B avant jointure
    C'est une solution aussi. Et elle est plus propre.
    Mais peut-être pas toujours aussi facilement identifiable ou compréhensible dans des requêtes complexes où on aime rassembler tout ce qui est purement filtre dans la clause where (surtout si ce filtre est construit dynamiquement).

    Bref, le langage SQL est un langage puissant, performant mais complexe et qui peut se révélé assez facilement contre-productif si on ne fait pas attention à ce que l'on fait.
    --- Sevyc64 ---

    Parce que le partage est notre force, la connaissance sera notre victoire

  15. #15
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    WinNew, bravo pour tes schémas très clairs !

    Par contre, je ne suis pas sûr de la validité du dernier.
    Fais des tests avec des données pour le vérifier.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  16. #16
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Oui WinNew c'est correct, mais dans le fond notez bien qu'on s'en fout.
    Vous êtes en train de vous demander s'il vaut mieux écrire 10/2 ou bien 0.5*10.

    Ecrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT ...
      FROM A
           LEFT  JOIN B ON A.KEY = B.KEY
           RIGHT JOIN C ON A.KEY = C.KEY;
    Est précisément, à mon sens, ce qu'il faut éviter de coder.

    Autant lever les ambiguïtés et écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT ...
      FROM C
           LEFT JOIN A ON A.KEY = C.KEY
           LEFT JOIN B ON B.KEY = A.KEY;

  17. #17
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sevyc64 Voir le message
    Dans le cas ou un enregistrement B serait bien retourné mais avec le champ en question nul, effectivement.

    C'est une solution aussi. Et elle est plus propre.
    Attention, certains SGBD (Access tout du moins) n'acceptent pas les valeurs littérales (ou paramètres) dans la clause "ON".

    Je trouve cela effectivement logique : si c'est une "valeur" et non un champ, alors il ne s'agit pas d'un élément de jointure, mais bien d'un élément de filtre, et n'a donc sa place que dans le "WHERE".
    On ne jouit bien que de ce qu’on partage.

  18. #18
    Membre régulier
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    WinNew, bravo pour tes schémas très clairs !

    Par contre, je ne suis pas sûr de la validité du dernier.
    Fais des tests avec des données pour le vérifier.
    Salut,

    J'ai vérifié en faisant des tests sur une base de test avant de poster

    Pour information, voici la petite base de test :

    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    SET foreign_key_checks = 0;
    DROP TABLE IF EXISTS citoyen;
    DROP TABLE IF EXISTS activite;
    DROP TABLE IF EXISTS voiture;
    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 voiture
    (
        id INT NOT NULL AUTO_INCREMENT,
        name VARCHAR(255),
        PRIMARY KEY(id),
        CONSTRAINT uc_name UNIQUE (name)
    )
    ENGINE=INNODB;
     
    INSERT INTO voiture SET name='Renault'; SELECT LAST_INSERT_ID() INTO @Renault;
    INSERT INTO voiture SET name='Peugeot'; SELECT LAST_INSERT_ID() INTO @Peugeot;
    INSERT INTO voiture SET name='BMW';     SELECT LAST_INSERT_ID() INTO @BMW;
    INSERT INTO voiture SET name='Toyota';  SELECT LAST_INSERT_ID() INTO @Toyota;
    INSERT INTO voiture SET name='Porshe';  SELECT LAST_INSERT_ID() INTO @Porshe;
     
    CREATE TABLE citoyen
    (
        id INT NOT NULL AUTO_INCREMENT,
        name VARCHAR(255),
        fk_activite INT,
        fk_voiture INT,
        PRIMARY KEY(id),
        FOREIGN KEY (fk_activite) REFERENCES activite(id),
        FOREIGN KEY (fk_voiture) REFERENCES voiture(id),
        CONSTRAINT uc_name UNIQUE (name)
    )
    ENGINE=INNODB;
     
    INSERT INTO citoyen SET name='Paul',      fk_activite=@comptable,  fk_voiture=@Renault;
    INSERT INTO citoyen SET name='Denis',     fk_activite=@comptable,  fk_voiture=@Renault;
    INSERT INTO citoyen SET name='Vincent',   fk_activite=@patissier,  fk_voiture=@Peugeot;
    INSERT INTO citoyen SET name='Eric',      fk_activite=@peintre,    fk_voiture=@Peugeot;  
    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,   fk_voiture=@Toyota; 
    INSERT INTO citoyen SET name='Kathy',     fk_activite=@vitrier,    fk_voiture=@Toyota;  
    INSERT INTO citoyen SET name='Stephanie';                        
    INSERT INTO citoyen SET name='Jean',                               fk_voiture=@BMW;
    A+

  19. #19
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Sinon, tu oublies le plus important :

    J'ai nommé l'absolument inutile "FULL OUTER JOIN" :

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    create table nom (pers_id int, nom varchar2(12));
    create table prenom (pers_id int, prenom varchar2(12));
    insert into nom values (1, 'DUPUIS');
    insert into nom values (2, 'DUPONT');
    insert into prenom values (1, 'Albert');
    insert into prenom values (3, 'Jean');
     
    select nvl(nom.pers_id, prenom.pers_id) pers_id, prenom.prenom, nom.nom
    from nom
    full outer join prenom on prenom.pers_id = nom.pers_id;

    Aujourd'hui, c'est la troisième 3 que je l'utilise : 2 fois afin de dire qu'il existe, et 1 fois parce que j'en ai réellement eu besoin, mais j'ai capitulé à cause des performances trop catastrophiques, j'ai préféré faire des requêtes imbriquées crades au possible, mais 1000x plus rapides.

    -- Edit : Ca me reviens, je m'en suis servi une fois "pour de vrai" dans le cadre d'une fusion de deux bases de données : j'avais la même clé dans plusieurs tables différentes, et il fallait créer une nouvelle table en joignant les données des deux tables. Mais le FULL OUTER JOIN, utilisé par personne (puisque méconnu, et facilement remplaçable par des syntaxes plus courantes), n'est absolument pas optimisé, et donc j'ai dû capituler très rapidement au profit d'une usine à gaz.
    On ne jouit bien que de ce qu’on partage.

  20. #20
    Membre régulier
    Profil pro
    Développeur informatique
    Inscrit en
    Mars 2008
    Messages
    80
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2008
    Messages : 80
    Points : 114
    Points
    114
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Oui WinNew c'est correct, mais dans le fond notez bien qu'on s'en fout.
    Vous êtes en train de vous demander s'il vaut mieux écrire 10/2 ou bien 0.5*10.

    Ecrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT ...
      FROM A
           LEFT  JOIN B ON A.KEY = B.KEY
           RIGHT JOIN C ON A.KEY = C.KEY;
    Est précisément, à mon sens, ce qu'il faut éviter de coder.

    Autant lever les ambiguïtés et écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT ...
      FROM C
           LEFT JOIN A ON A.KEY = C.KEY
           LEFT JOIN B ON B.KEY = A.KEY;


    Salut,

    Oui, effectivement, autant utiliser la même démarche de façon systématique...

    Dans le cas d'une "suite de relations linéraire", il est toujours possible de partir d'une extrémité pour aller vers l'autre. Dans ce cas, il est possible d'utiliser systématiquement le même type de jointure (uniquement du LEFT ou du RIGHT) pour joindre toutes les tables.



    Mais, dans le cas d'un ensemble de relations "non linéaires", il me semble que l'on est obligé d'utiliser les deux types de jointure (LEFT JOIN et RIGHT JOIN) simultanément (pour joindre toutes les tables).



    En fait, non. Ce que je viens d'écrire plus haut est faux... On ne peut pas généraliser. Tout dépend de ce que l'on veut faire.


    Denis

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Plusieurs left join ou right join
    Par devman2011 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 09/03/2012, 07h59
  2. left join et right join
    Par huître dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 13/10/2011, 21h25
  3. left join , right join et inner join ?
    Par amine003 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 05/12/2008, 17h25
  4. Fonction Left join, Right Join
    Par chandlerbing77 dans le forum Access
    Réponses: 2
    Dernier message: 22/06/2006, 16h36
  5. Réponses: 4
    Dernier message: 28/10/2005, 20h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo