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 :
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.
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 | ---------
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.
Certains voient déjà peut etre le problème se profiler :
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');
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 :
Le résultat de la requete précédente :
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 | ------------------------- ----------------- -----------------------
(j'ai ajouté lalid qui correspond à labels_objects.label_id, pour qu'on pige bien le pb)
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 !
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 | ------------------------------------
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) )
Partager