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

Requêtes PostgreSQL Discussion :

Join et conditions


Sujet :

Requêtes PostgreSQL

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 66
    Points : 63
    Points
    63
    Par défaut Join et conditions
    Salut tout le monde,

    J'ai un problème de requete à base de JOIN que je souhaite élucider, mais je n'y arrive pas.

    J'ai deux tables, reliées par une table pivot :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    ---------        ----------------        ---------        
    |objects|        |labels_objects|        |labels |
    ---------        ----------------        ---------
    |id     |        |label_id      |        |id     |
    |datas  |        |object_id     |        |type   |
    ---------        ----------------        |datas  |
                                             ---------
    Rien de compliqué, on a des objets, des étiquettes, et on met des étiquettes sur les objets. C'est une relation n-n, un objet peut avoir plusieurs étiquettes et une étiquette peut estampiller plusieurs objets.

    Attention c'est là que ca se complique :

    Je travaille sur les objets. Je souhaite récupérer la liste des objets, et quand il y a une etiquette de type "rouge" sur un objet, je souhaite récupérer l'étiquette. Quand il n'y a pas d'étiquettes, je souhaite récupérer l'objet quand meme.

    Pour cela je procède de la façon suivante.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT objects.id AS oid, labels.id AS lid, labels.type FROM objects
    LEFT JOIN labels_objects ON (labels_objects.object_id = objects.id)
    LEFT JOIN labels ON (labels.id = labels_objects.label_id AND type = 'rouge');
    Certains voient déjà peut etre le problème se profiler :

    Je récupère bien tout ce que je veux, mais si des objets appartiennent à plusieurs labels, rouge ou non, et bien je récupère ces objets mais en de multiples exemplaires ! Je vais donner un exemple pour illustrer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    -----------------        -----------------------            -------------------------
    |    objects    |        |   labels_objects    |            |       labels          |
    -----------------        -----------------------            -------------------------
    |id       datas |        |label_id    object_id|            |id       type     datas|
    |---------------|        |---------------------|            |-----------------------|
    |1        pomme |        |1           1        |            |1        rouge    0x53 |    
    |2        poire |        |1           2        |            |2        vert     0x58 |
    |3        banane|        |2           2        |            -------------------------
    -----------------        -----------------------
    Le résultat de la requete précédente :
    (j'ai ajouté lalid qui correspond à labels_objects.label_id, pour qu'on pige bien le pb)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ------------------------------------
    |oid     lid     lalid        type |
    ------------------------------------
    |1       1       1            rouge|
    |1       NULL    2            NULL |
    |2       NULL    2            NULL |
    |3       NULL    NULL         NULL |
    ------------------------------------
    Ce qui m'embete c'est le deuxieme rang, je voudrais le dégager. Cela vient du JOIN sur la table labels_objects. J'aimerai m'en défaire sans avoir recours à trop de de conditions WHERE car l'exemple est bien plus simple que la réalité, et je m'en sors pas avec des where à ralloooooonge : _ AND ( ( _ AND _ ) OR _ ) ... Je veux aussi éviter les DISTINCT ON () aussi car je ne maitrise pas bien le rang qu'il choisit de me remonter, parfois j'ai celui avec l'étiquette, parfois non !

    Voyez vous une solution, idéalement à placer sur le JOIN, qui me permettrai de résoudre ce problème ?

    Merci d'avance !

    Bonne soirée.

    Guiz

    PS : pour les courageux, voici les scripts CREATE afin de reproduire l'exemple. Par souci de simplicité, toutes les
    relations ne figurent pas. Les inserts sont a faire à la main, mais bon, c'est vraiment pas long.
    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
     
    CREATE TABLE labels
    (
      id serial NOT NULL,
      "type" character varying,
      datas character varying,
      CONSTRAINT labels_pkey PRIMARY KEY (id)
    )
     
    CREATE TABLE labels_objects
    (
      label_id integer NOT NULL,
      object_id integer NOT NULL,
      CONSTRAINT labels_objects_pkey PRIMARY KEY (label_id, object_id)
    )
     
    CREATE TABLE objects
    (
      id serial NOT NULL,
      datas character varying,
      CONSTRAINT objects_pkey PRIMARY KEY (id)
    )

  2. #2
    Rédacteur
    Avatar de David55
    Homme Profil pro
    Ingénieur informatique
    Inscrit en
    Août 2010
    Messages
    1 542
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 1 542
    Points : 2 808
    Points
    2 808
    Par défaut
    Bonsoir,

    Qu'est ce qui t’empêche de faire un INNER JOIN?

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    J'ai peur de dire une bêtise là mais un inner join ne va pas me sélectionner les objets qui n'ont aucun label, si ?

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    Salut,

    Je confirme ma réponse d'hier soir, je ne comprends pas comment un INNER JOIN pourrait sélectionner les lignes qui ne remplissent pas forcément la condition. Si tu as une explication n'hésite pas à me la fournir.

    Néanmoins, merci pour ta réponse.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    Je viens de trouver une solution qui pourrait répondre à mon problème, c'est d'utiliser des subqueries dans le JOIN (c'est peut etre ce que David55 suggérait). Je ne savais même pas que ça se faisait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT objects.id AS oid, temp.id AS lid, temp.type FROM objects
    LEFT JOIN 	
    	(SELECT labels.id, labels.type, labels_objects.object_id FROM labels_objects JOIN labels ON (labels.id = labels_objects.label_id)) temp 
    ON (objects.id = temp.object_id AND temp.type = 'rouge')
    Je réfléchi encore un peu, et si je ne trouve pas mieux je placerai cela en résolu. En attendant je suis toujours ouvert à vos commentaires.

    Merci

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Points : 2 890
    Points
    2 890
    Par défaut
    Tu peux aussi faire:
    SELECT des objets ayant un label rouge
    UNION
    SELECT des objets n'ayant aucun label

    Pour les objets n'ayant aucun label, c'est requêtable avec une clause NOT IN, ou bien avec un objects LEFT JOIN label_objects et condition IS NULL sur la colonne de jointure.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 66
    Points : 63
    Points
    63
    Par défaut
    Finalement je suis très satisfait de ma méthode. Mes requêtes ne sont pas beaucoup plus complexes, et cela fonctionne très bien !

    estofilo, ta solution fonctionne, mais m'oblige à taper deux requêtes de sélection. Je préfère donc la mienne.

    Merci pour vos réponses.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Inner join avec condition
    Par fguigui dans le forum Langage SQL
    Réponses: 7
    Dernier message: 09/04/2012, 19h40
  2. Problème LEFT JOIN avec conditions ?
    Par Zane dans le forum Requêtes
    Réponses: 8
    Dernier message: 05/03/2010, 16h29
  3. left outer join avec condition
    Par fisto dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 14/08/2007, 08h52
  4. Outer join avec condition OR
    Par Ujitsu dans le forum Langage SQL
    Réponses: 1
    Dernier message: 28/03/2007, 23h08
  5. Oraclei : LEFT JOIN et conditions
    Par alexadvance dans le forum Oracle
    Réponses: 9
    Dernier message: 02/11/2005, 15h22

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