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

MySQL Discussion :

Requête qui renvoie uniquement les produits possédant X catégories - Pb de perf


Sujet :

MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 50
    Par défaut Requête qui renvoie uniquement les produits possédant X catégories - Pb de perf
    Bonjour,

    J'ai une base avec des produits et des catégories de produits. Un produit peut appartenir à X catégories de produits en même temps.

    Je cherche à récupérer la liste des produits qui possèdent toutes les catégories recherchées par le visiteur. Sous MySQL, il y a pas de intersect alors j'ai trouvé une solution en faisant une sous requête, par exemple pour 2 catégories, ça donne ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT products.ID, products.title FROM products
    LEFT JOIN categories ct ON products.ID = ct.product_id
    WHERE ct.category_id = 41
    AND products.ID IN (
        SELECT products.ID FROM products
        LEFT JOIN categories ct ON products.ID = ct.product_id
        WHERE ct.category_id = 66
    )
    GROUP BY products.ID
    Ca fonctionne. Le pb, c'est que si je le fais sur la vraie base (j'ai simplifié les tables pour l'exemple), la requête met 10 secondes à s'exécuter sur le serveur, c'est hyper long.

    J'ai pensé à une solution qui serait de simplement faire un OR sur les catégories, ce qui me renverrait toutes les entrées contenant l'une ou l'autre de ces catégories sans être groupées. Et ensuite de filtrer en PHP la liste pour récupérer uniquement les entrées ayant les 2 catégories.

    Je passe à coté d'un truc ? Je suis pas très bon en SQL donc toutes les réponses sont bienvenues

    Merci pour vos retours.

  2. #2
    Membre averti
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 50
    Par défaut
    Il semble qu'il faudrait utiliser une table temporaire (ou un assimilé de ça). Je vais essayer ça sur mon pb.

    Réponses toujours bienvenues

  3. #3
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Par défaut
    Bonjour

    essayez ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    SELECT 
    		products.ID
    	,	products.title 
    FROM 		products
    INNER JOIN 	categories ct 
    	ON 		products.ID = ct.product_id
    WHERE		 ct.category_id IN (41,66)
    GROUP BY 
    		products.ID
    	,	products.title 
    HAVING 		COUNT(*) = 2

  4. #4
    Membre averti
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 50
    Par défaut
    Bonjour aieeeuuuuu,

    Merci pour la réponse. J'avais trouvé le HAVING COUNT aussi. Le pb est que j'utilise pas un IN mais un LIKE. Ca change qq chose.

    En effet, si j'ai une catégorie "chat" et une "alimentation-chat" et une autre "croquette" pour un produit et que l'utilisateur tape "croquette chat", comme j'utilise un LIKE "%chat%" dans la requête et pas un IN ("chat", ...), je vais me retrouver avec 3 entrées pour ce produit et non uniquement 2 et donc le HAVING COUNT (*) = 2 va pas le remonter, alors que mon produit est cohérent avec la recherche de l'internaute.

    Je sais pas si c'est très clair...

    Mais ce que vous dites fonctionne très bien si je fais une recherche exacte avec un IN et pas un LIKE.

    Le pb est que c'est une pour une recherche textuelle. Donc si l'utilisateur tape "croquette cha" et pas "croquette chat", je veux que ça puisse lui remonter quand même les produits de croquettes pour chat.

    Plus j'avance et plus je me dis que mon pb est pas si simple en fait...

  5. #5
    Expert éminent
    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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 818
    Billets dans le blog
    14
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    JOIN categories ct ON products.ID = ct.product_id
    Vous avez une clé étrangère référençant le produit dans la table des catégories ? !!!
    Ceci voudrait dire qu'une catégorie ne peut avoir qu'un seul produit ?
    N'y a t-il pas plutôt une table associative entre les produits et les catégories ?

    Ceci étant dit, vous avez deux problèmes différents :
    1) Quelles sont les catégories de produits concernées par le texte tapé par l'utilisateur ?
    Il faut déjà voir comment, dans votre programme, vous traduisez la demande de l'utilisateur en catégories à rechercher.
    Pour reprendre votre exemple, "croquette cha", est-ce que vous décomposez la demande en mots signifiants ?
    Alors vous aurez besoin, pour répondre à ce premier besoin, de ce type de requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT DISTINCT name
    FROM categories
    WHERE name LIKE '%croquette%'
    	OR name LIKE '%cha%'
    Sur le même principe, vous pouvez savoir combien de catégories sont concernées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT COUNT(DISTINCT name) AS nb_categories
    FROM categories
    WHERE name LIKE '%croquette%'
    	OR name LIKE '%cha%'
    2) Quels sont les produits qui sont rattachés à toutes les catégories concernées par la demande de l'utilisateur ?
    Cette fois, il faut utiliser le principe donné par aieeeuuuuu.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    SELECT p.ID, p.title
    FROM products p
    INNER JOIN produit_categorie pc ON pc.id_produit = p.ID
    	INNER JOIN categorie c ON c.ID = pc.id_categorie
    WHERE c.name LIKE '%croquette%'
    	OR c.name LIKE '%cha%'
    GROUP BY p.ID, p.title
    HAVING COUNT(DISTINCT c.ID) =
    (
    	SELECT COUNT(DISTINCT name) AS nb_categories
    	FROM categories
    	WHERE name LIKE '%croquette%'
    		OR name LIKE '%cha%'
    )
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole, en retraite... mais toujours Autoentrepreneur à l'occasion.
    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
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    22 002
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 22 002
    Billets dans le blog
    6
    Par défaut
    Personne n'a vu le GROUP BY imbécile ? Bravo les mecs !!!!!

    Encore une fois le forum MySQL a égayé ma journée !!!!

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  7. #7
    Membre averti
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    50
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 50
    Par défaut
    Bonjour Philippe,

    Merci pour la réponse et pour la sous requête avec sur le HAVING. J'avais pas du tout pensé à un truc comme ça.

    Pour la table associative, vous avez raison, il y en a une entre les catégories et les produits. J'avais essayé de simplifier pour poster le pb mais j'ai peut être trop simplifié.

    Pour en revenir à votre réponse, ça marche presque mais le pb est un peu le même que si j'avais directement mis HAVING COUNT(*) >= 2.

    Pourquoi ? parce qu'imaginons que j'ai ces 4 catégories: chat, croquette, transport-chat et alimentation-chat. 3 contiennent "chat" et une "croquette".
    Imaginons que j'ai:
    - un produit 1 qui a "croquette", "alimentation-chat" et "chat"
    - un produit 2 qui a "chat" et "transport-chat"
    - un produit 3 qui a "chat" et "alimentation-chat"

    Du coup, si j'exécute votre requête pour simuler que l'utilisateur tape "croquette" et "cha", ça devrait me remonter que le premier produit mais ça remonte rien car la sous requête du HAVING COUNT dénombre 4 catégories qui possèdent soit croquette soit "%cha%".

    Si par contre j'utilise mon HAVING COUNT(*) >=2, ça va remonter le produit 1 mais aussi les 2 autres car les deux autres ont aussi 2 catégories qui répondent aux exigences (contenir croquette ou %cha%).

    Je sais pas si c'est très clair. Je sais pas vraiment s'il y a une solution autre qu'une grosse requête avec des AND et des sous requêtes qui fait 10 secondes à s'exécuter.

    Merci en tous cas pour le temps pris pour votre réponse.

Discussions similaires

  1. Réponses: 8
    Dernier message: 15/06/2015, 10h34
  2. Requête qui renvoie les locks sur un schéma
    Par LNA97 dans le forum Administration
    Réponses: 1
    Dernier message: 18/03/2015, 09h46
  3. Réponses: 7
    Dernier message: 12/03/2015, 06h23
  4. Requête qui renvoie les valeurs les plus souvent affichés
    Par athos7776 dans le forum Requêtes et SQL.
    Réponses: 9
    Dernier message: 25/07/2007, 17h54

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