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