Jointure entre deux tables via une table de liaison

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Salut à tous,

Pour une application j’ai conçu une base de données (peut-être perfectible) et j’ai un petit soucis de jointure.

J’ai une table produit qui contient la liste de mes produits avec diverses informations. J’ai une table surface qui contient une liste de surface (tissu, cuir etc).

J’ai enfin une dernière table pour faire la liaison entre les deux que j’ai nommée produit_surface. Dedans j’ai un id_produit et un id_surface.

Je l’ai conçu comme ça car un produit peu avoir une ou plusieurs surfaces.

Mais au moment de récupérer mes données j’ai l’impression d’avoir loupé quelque chose. Avec mes jointures j’arrive à récupérer mes données mais ça ne me convient pas.

Je voudrais récupérer chaque produit une seule fois avec la liste des surfaces auxquels il correspond. Pour l’instant j’obtiens par exemple 3 fois le même produit si il correspond à 3 surfaces.

Voici ma requête :

1
2
3
4
SELECT p.id, p.produit, p.prix, p.stock, p.description, p.image, s.surface, s.id AS id_surface
FROM `surface` AS `s` 
RIGHT JOIN `produit_surface` AS `ps` ON ps.surface = s.id
RIGHT JOIN `produit` AS `p` ON p.id = ps.produit

J’ai bien peur que la conception de ma base de donnée soit à l’origine de mon problème. Avez vous une idée ? Merci d’avance ;)

+0 -0
Auteur du sujet

Merci de ta réponse, je suis déjà tombé sur ce schéma mais je n’ai spécialement trouvé de cas qui correspondait.

J’ai utilisé un Right Join qui me permet de récupérer les informations de ma table produit.

+0 -0

Je voudrais récupérer chaque produit une seule fois avec la liste des surfaces auxquels il correspond. Pour l’instant j’obtiens par exemple 3 fois le même produit si il correspond à 3 surfaces.

En soit tu ne peux pas : mysql est un système relationnel. Si tu veux obtenir une sorte de "tableau de surface" dans un objet produit, il faudra soit utiliser un ORM soit coder la logique de rassemblement à la main.

Ou alors il faudra faire autant de requêtes que tu as de produits.

+0 -0

Cette réponse a aidé l’auteur du sujet

Une solution possible avec GROUP_CONCAT :

1
2
3
4
5
6
7
8
9
SELECT  produit.*,
        GROUP_CONCAT(surface.surface) as surfaces,
        GROUP_CONCAT(surface.id) as id_surfaces
FROM produit
JOIN produit_surface
    ON produit.id = produit_surface.produit
JOIN surface
    ON surface.id = produit_surface.surface
GROUP BY produit.id;

Édité par yoch

+0 -0
Auteur du sujet

Je voudrais récupérer chaque produit une seule fois avec la liste des surfaces auxquels il correspond. Pour l’instant j’obtiens par exemple 3 fois le même produit si il correspond à 3 surfaces.

En soit tu ne peux pas : mysql est un système relationnel. Si tu veux obtenir une sorte de "tableau de surface" dans un objet produit, il faudra soit utiliser un ORM soit coder la logique de rassemblement à la main.

Ou alors il faudra faire autant de requêtes que tu as de produits.

artragis

Il me semblait bien que j’essayais de faire un truc impossible. Je vais peut-être revoir ma base de donnée dans ce cas.

Une solution possible avec GROUP_CONCAT :

1
2
3
4
5
6
7
8
9
SELECT    produit.*,
      GROUP_CONCAT(surface.surface) as surfaces,
      GROUP_CONCAT(surface.id) as id_surfaces
FROM produit
JOIN produit_surface
  ON produit.id = produit_surface.produit
JOIN surface
  ON surface.id = produit_surface.surface
GROUP BY produit.id;
yoch

Super ! ça fonctionne effectivement. Merci beaucoup je ne connaissais pas l’utilisation de GROUP_CONCAT.

+0 -0

Salut, J’arrive peut-être un peu tard, mais j’aimerais soumettre une alternative supplémentaire.

Ce que tu cherches à faire s’appelle du many to many, parce que plusieurs éléments peuvent avoir une relation avec plusieurs autres éléments. L’alternative que je vous propose consiste à réaliser deux requêtes. La première sur la table produit, puis la seconde sur la table intermédiaire produit_surface avec une jointure sur la table surface.

On commence par récupérer les produits

1
SELECT id, produit, prix, ... FROM produit

Puis on récupère les surfaces

1
2
3
4
SELECT surface.id, surface.surface
FROM produit_surface
LEFT JOIN surface ON surface.id = produit_surface.surface
WHERE produit_surface.produit IN (/* liste des ids */)

où la liste des ids est l’ensemble des id des produits

Ensuite, on assemble les produits et les surfaces avec une boucle.

Pourquoi faire ça ?

L’exemple des meubles et leur matériaux n’est pas très pertinent pour faire deux requêtes, un GROUP_CONCAT fonctionne parfaitement, et est sans doute plus performant. Un bon exemple de many to many où deux requêtes sont pertinentes est un blog scientifique, où un article peut avoir plusieurs auteurs, et un auteur peux écrire plusieurs articles.

Dans ce cas plus complexe, on ne peut se limiter à GROUP_CONCAT (entre autres parce que la longueur limite est 1ko), et faire "autant de requêtes que tu as de produits" est inconcevable. Faire deux requêtes est donc un excellent compromis.

J’espère ne pas avoir été hors sujet, amicalement, Gautier

<o/

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte