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 :

Requête select produits uniques plusieurs tables liées


Sujet :

Langage SQL

  1. #1
    Membre régulier Avatar de Stephane_br
    Inscrit en
    Septembre 2005
    Messages
    222
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 222
    Points : 83
    Points
    83
    Par défaut Requête select produits uniques plusieurs tables liées
    Bonjour,

    Je viens vers vous pour une piste concernant une requête sur des produits d'une vente en ligne.

    En gros, j'ai une grosse requête qui doit me sortir les produits d'une sous-catégorie données, et dans cette requête, je dois remonter tout un tas de colonnes en une seule requête grâce à une procédure stockée.

    Or la table produits est liée à différentes tables, reliées entre-elles par des jointures.
    Et le souci, c'est que ma table principale "Produits", et bien je ne dois remonter qu'une seule fois chaque produit dans le listing bien sûr, sauf que comme chaque produit peut être lié plusieurs fois, cela me remonte des produits en double. Avec un distinct, le souci, d'une c'est trop long, de deux, comme les id que je dois récupérer dans ma requête sont différent, un distinct ne me permet pas de supprimer les "faux doublons".

    En fait, un produit est lié à des caractéristiques. ces caractéristiques sont liées à un prix.
    Du coup, pour, par exemple, un pull-over qui est mon "produit", je peux avoir la caractéristique "bleu", une autre "rouge" et chaque caractéristique est liée à un prix.
    Quand je fais ma requête, cela me ressort 2 fois le pull-over bien-sur en rouge et en bleu.

    mais comment faire pour ne sortir qu'une fois le pull-over en ne prenant que la première caractéristique ? je suis obligé pour calculer le prix ! si possible en triant sur la caractéristique la moins chère.
    Pour infos, je vous donne un schéma rapide de ma base.

    Egalement ma requête actuelle (simplifiée pour comprendre rapidement le problème) :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    select * from PRODUIT as p
    inner join pivot_cat_produits as piv on piv.id_produit = p.id
    inner join sous_categorie as cs on cs.id = piv.id_sous_cat
    inner join categorie as c on c.id = cs.id_parent
    inner join caracteristiques as pf on pf.id_produit = p.id
    inner join prix as px on px.id_caracteristique = pf.id
     
    where (.....) and cs.id=120
    order by cs.produit_classement
    Images attachées Images attachées  

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 793
    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 793
    Points : 34 024
    Points
    34 024
    Billets dans le blog
    14
    Par défaut
    Avec un distinct, le souci, d'une c'est trop long
    Vos tables sont-elles correctement indexées ?
    Quelle volumétrie de données avez-vous ?

    comme les id que je dois récupérer dans ma requête sont différent, un distinct ne me permet pas de supprimer les "faux doublons".
    Les ID de quoi ?
    Votre besoin est trop vague.

    mais comment faire pour ne sortir qu'une fois le pull-over en ne prenant que la première caractéristique ?
    Comment déterminez-vous la première et les suivantes ?

    je suis obligé pour calculer le prix ! si possible en triant sur la caractéristique la moins chère.
    Cela veut-il dire que vous cherchez, par exemple, le pull over le moins cher ?
    Encore une fois, votre besoin est exprimé trop vaguement pour qu'on puisse vous aider efficacement.
    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 !

  3. #3
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 088
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 088
    Points : 38 395
    Points
    38 395
    Billets dans le blog
    9
    Par défaut
    Bonsoir,

    En supposant que tous vos critères de jointures sont sargables, faute de description exacte de vos tables et index (pas de DDL fourni); qu'en est il de vos critères de filtrage, autre facteur primordial de performances ?

    Fournissez le prédicat where complet et les index pour les colonnes de filtrage
    Vérifiez que celui ci ne contient pas de prédicat "<>" de like avec un % en début de chaine, ou tout autre élément rendant les index inéligibles
    Vérifiez également le facteur de filtrage, une colonne qui ne contient que très peu de valeurs distinctes n'est pas filtrante
    Enfin quelques éléments de volumétrie seraient les bienvenus

    EDIT : et remplacez "SELECT * " par la liste exacte des colonnes dont vous avez besoin. Avec 'SELECT *' vous transportez tout un tas de colonnes inutiles, à commencer par les colonnes de jointure que vous avez à minima 2 fois, ce sera déjà ça de gagné. Sans compter que select * ne produit pas le même résultat si les tables ou vues changent

  4. #4
    Membre régulier Avatar de Stephane_br
    Inscrit en
    Septembre 2005
    Messages
    222
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 222
    Points : 83
    Points
    83
    Par défaut
    Bonjour et merci pour votre réponse.

    Concernant les index, je pense que c'est ok car je les ai vérifié avec l'outil d'analyse de Sql. Après ce n'est peut-être pas parfait.
    Mon problème ne vient pas forcément des performances, mais plutôt de l'écriture de ma requête pour sortir ce que je veux (voir mon explication ci-après).

    Concernant les id, d'après mon exemple (image ci-dessus), mon select doit comprendre obligatoirement :

    *********
    - l'id du produit
    - quelques infos du produit (son nom, sa description, etc...)
    *********
    - l'id de la caractéristique
    - une référence dans la caractéristique
    - un texte dans la caractéristique
    *********
    - le prix de la caractéristique
    - (en option si il y a une promo)
    *********
    - l'id de la sous-catégorie
    - le nom de la sous-catégorie
    *********
    - l'id de la catégorie
    - le nom de la catégorie
    *********


    Concernant le where :
    >> dans ma requête, je vérifie juste que dans chaque table, la ligne sélectionnée doit être active => je me base sur une colonne de type "bit" (active=1)
    >> je filtre ensuite juste sur l'id de la sous-catégorie pour ne remonter que les produits de cette sous-catégorie.

    Ce qui donne
    where produit.actif=1, caracteristique.active=1, prix.actif=1, souscatégorie.active=1, categorie.active=1 and soucategorie.id=120
    l'order by doit se positionner sur une colonne de classement de type int qui se trouve dans mon pivot (+ sur le prix le moins cher de la caractéristique).
    soit pour le moment :
    order by pivot.classement desc

    J'ai besoin de tout cela pour mes traitement derrière. Or, un produit peut avoir plusieurs caractéristiques et chaque caractéristique à un prix différent.
    Ce qui fait que si je fais un select distinct sur l’ensemble de ces tables avec des inner join, je me retrouve par exemple avec une liste de 2 produits "identique" si ce produit possède 2 caractéristiques différentes.

    Quand je dis "identique", je veux dire que pour moi, un pull-over, qu'il soit bleu, jaune our rouge, je dois pouvoir le considérer comme un seul et même produit "techniquement" parlant.
    Je ne dois remonter qu'un seul produit même si il possède plusieurs caractéristiques. (et donc un seul prix => sur le site, je dois mettre : à partir de...) => le moins cher).

    Concernant la volumétrie, la base totale contient presque 10000 caractéristiques de produits environ soit 10000 produits environ. C'est ce que je sort actuellement avec ma requête.
    Si je les regroupe par une caractéristique par produit, je devrais tomber dans les 4000 produits environ. C'est ce que je veux obtenir avec ma requête.

    Est-ce plus précis comme explication ?

    Citation Envoyé par CinePhil Voir le message
    Vos tables sont-elles correctement indexées ?
    Quelle volumétrie de données avez-vous ?


    Les ID de quoi ?
    Votre besoin est trop vague.


    Comment déterminez-vous la première et les suivantes ?


    Cela veut-il dire que vous cherchez, par exemple, le pull over le moins cher ?
    Encore une fois, votre besoin est exprimé trop vaguement pour qu'on puisse vous aider efficacement.

  5. #5
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 793
    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 793
    Points : 34 024
    Points
    34 024
    Billets dans le blog
    14
    Par défaut
    Je ne dois remonter qu'un seul produit même si il possède plusieurs caractéristiques. (et donc un seul prix => sur le site, je dois mettre : à partir de...) => le moins cher).
    Donc vous cherchez, par produit, la caractéristique la moins cher ?
    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
    SELECT p.id AS id_produit,
    	p.nom AS nom_produit,
    	p.description AS description_produit,
    	sc.id AS id_sous_categorie,
    	sc.nom AS nom_sous_categorie,
    	cat.id AS id_categorie,
    	cat.nom AS nom_categorie
    	car.reference AS reference_caracteristique,
    	car.texte AS texte_caracteristique,
    	t1.prix_mini
    FROM produit p
    INNER JOIN 	pivot_categorie_produit cp ON cp.id_produit = p.id
    	INNER JOIN sous_categorie sc ON sc.id = cp.id_sous_cat
    		INNER JOIN categorie AS cat ON cat.id = sc.id_parent
    INNER JOIN
    (
    	SELECT c.id_produit,
    		MIN(px.prix) AS prix_mini
    	FROM caracteristique c
    	INNER JOIN prix px ON px.id_caracteristique = c.id
    	GROUP BY c.id_produit
    ) t1 ON t1.id_produit = p.id
    	INNER JOIN 
    	(
    		SELECT car.id AS id_caracteristique,
    			car.reference AS reference_caracteristique,
    			car.texte AS texte_caracteristique,
    			car.id_produit,
    			px2.prix
    		FROM caracteristique car 
    		INNER JOIN prix px2 ON px2.id_caracteristique = car.id
    	) t2 
    		ON t2.id_produit = t1.id_produit
    		AND t2.prix = t1.prix_mini
    WHERE sc.id = :id_sous_categorie
    À tester...

    NOTA : Votre table pivot_categorie_produit implique qu'un produit peut faire partie de plusieurs sous-catégories, ce qui peut entraîner plusieurs lignes pour le même produit dans le résultat de la requête.
    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 !

  6. #6
    Membre régulier Avatar de Stephane_br
    Inscrit en
    Septembre 2005
    Messages
    222
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 222
    Points : 83
    Points
    83
    Par défaut
    Merci pour votre réponse.
    En effet, un produit peut se trouver dans plusieurs sous-catégories.

    Je vous remercie pour votre réponse. Cela semble être exactement ce que je cherchais à faire. je n'avais pas pensé à faire avec les inner join comme cela...
    J'adapte cela sur mon site avec mes tables et reviens ici pour faire un retour après quelques tests.

    Mais déjà, je vous remercie énormément ! Cela m'aide beaucoup.
    Cordialement.

  7. #7
    Membre régulier Avatar de Stephane_br
    Inscrit en
    Septembre 2005
    Messages
    222
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 222
    Points : 83
    Points
    83
    Par défaut
    Bon, je n'arrive pas à solutionner mon problème car avec les inner join construits comme dans votre exemple, cela me remonte exactement le même résultat que ma requête originale, à savoir tous les produits (avec les "doublons").

    Je comprend pas pourquoi avec un inner join cela ne fonctionne pas.
    Car en effet, si j'exécute seulement (à part) le select dans votre requête pour le premier "inner join" (t1) en y ajoutant la sous-catégorie à la main juste pour tester ce qu'elle ressort et vérifier, j'ai bien le bon nombre de produits désiré sans aucun doublons.

    Donc en toute logique, cet inner join devrait me supprimer les doublons ?
    Pourquoi l'inner join semble ne pas vouloir fonctionner ?
    Il me ressort quand même les produits qui ne se trouvent pas dans ce résultat (t1) (voir exemple ci-dessous) ....
    comment il fait pour jointer des produits qui n'existent pas ?

    ma requête :

    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
      select p.*
     from produits p
     inner join pivot_produits_sous_categories as pp on pp.id_produit = p.id 
     inner join sous_categories as s on s.id = pp.id_ss_categorie
     inner join categories as c on c.id = s.id_parent 
     inner join ( SELECT pf.id_produit, MIN(px.prixHT) AS prix_mini
    	FROM caracteristiques pf
    	inner join prix px on px.id_caracteristique = pf.id
    	GROUP BY pf.id_produit
     ) t1 ON t1.id_produit = p.id
     
     inner join ( SELECT car.id AS id_caracteristique,
    	car.ref AS reference_caracteristique,
    	car.title AS texte_caracteristique,
    	car.id_produit,
    	px2.prixHT
    	FROM caracteristiques car 
    	INNER JOIN prix px2 ON px2.id_caracteristique = car.id
     ) t2 ON t2.id_produit = t1.id_produit AND t2.prixHT = t1.prix_mini
     where s.id = 120

    Il y a un truc quelque part que je ne comprends pas...
    Je continue de chercher....

Discussions similaires

  1. Réponses: 4
    Dernier message: 20/05/2010, 13h28
  2. [1.x] Flux RSS + requête entre plusieurs tables liées
    Par blasil64 dans le forum Symfony
    Réponses: 3
    Dernier message: 09/01/2010, 11h30
  3. [Requête SQL] - Select count avec plusieurs tables
    Par Pithonnette dans le forum SQL
    Réponses: 7
    Dernier message: 25/06/2009, 20h19
  4. [VB]Utiliser plusieurs table liées avec un contrôle Data
    Par yangoal25 dans le forum VB 6 et antérieur
    Réponses: 25
    Dernier message: 21/02/2006, 16h36
  5. select multiple sur plusieurs tables
    Par syl2095 dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 08/12/2004, 16h48

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