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

Requêtes MySQL Discussion :

le or ou le in() fonctionne mais non fiable !!


Sujet :

Requêtes MySQL

  1. #1
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut le or ou le in() fonctionne mais non fiable !!
    le fait de faire un having avec un count n'est là que pour se donner bonne conscience mais c'est pourri car des qu'une order avec un status égale à 8 a plusieurs status dans la base le count sera > à 1 donc tu vas croire que c'est bon cependant rien ne garantie que les deux status attendu sont bien présent pour les mêmes ID !!

    la seule et unique solution est plusieurs jointures sur la même table ce que l'auteur du poste avait lui même proposé.

    ex :
    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
    select  distinct C.titre
    from RECETTES C
    inner join PIVOT_RECETTES_INGREDIENTS as D1 on D1.RECETTE_ID=C.ID
    inner join PIVOT_RECETTES_INGREDIENTS as D2 on D2.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D3 on D3.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D4 on D4.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D5 on D5.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D6 on D6.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D7 on D7.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D8 on D8.RECETTE_ID=C.ID
    where 1=1
    and D1.INGREDIENT_ID = '1'
    and D2.INGREDIENT_ID = '99'
    --and D3.INGREDIENT_ID = '112'
    --and D4.INGREDIENT_ID = '146'
    --and D5.INGREDIENT_ID = '171'
    --and D6.INGREDIENT_ID = '204'
    --and D7.INGREDIENT_ID = '273'
    --and D8.INGREDIENT_ID = '131'

  2. #2
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 134
    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 134
    Points : 38 557
    Points
    38 557
    Billets dans le blog
    9
    Par défaut
    Votre souci est loin d'être clair !
    Mais une chose est certaine c'est que si vous n'obtenez pas le résultat attendu avec OR ou avec IN, c'est que votre requête est mal construite

    Fournissez un extrait de votre jeu de données, la requête exécutée, le résultat attendu et le résultat obtenu

  3. #3
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut certe
    Je vous comprend

    en fait je n'ai pas ouvert de poste j'ai simplement répondu à ce poste (lien en bas de mon message) ou j'ai jugé que la réponse donnée etait fausse et mon message explicité pourquoi et donne la bonne réponse.

    ce qui m'a valu la création de ce poste

    J'attends qu'un modo remette cette réponse dans le fils initiale sinon je supprime ce poste et laisse l'autre avec une réponse fausse ce qui est dommage.

    Merci quand même.

    topic initial :
    https://www.developpez.net/forums/ne....php?p=4661928

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    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 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Le problème est que vous avez réveillé une discussion vieille de 9 ans pour en plus donner une réponse pour le moins absconse, voire fausse.

    Si vous n'avez pas de problème à soumettre, vous pouvez effectivement supprimer cette nouvelle discussion ou demander à ce qu'un modérateur le fasse.
    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 !

  5. #5
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 380
    Points : 19 062
    Points
    19 062
    Par défaut
    Salut à tous.

    Citation Envoyé par nassertom
    le fait de faire un having avec un count n'est là que pour se donner bonne conscience
    Bonne conscience de quoi ? Savez-vous au moins à quoi peut servir un having dans un count ?

    Citation Envoyé par nassertom
    mais c'est pourri
    Qu'est-ce qui est pourri ?
    Le fait de mettre un count puis de sélectionner les lignes ayant disons >1 n'est pas en soi une erreur.

    Citation Envoyé par nassertom
    car des qu'une order avec un status égale à 8 a plusieurs status dans la base le count sera > à 1 donc tu vas croire que c'est bon cependant rien ne garantie que les deux status attendu sont bien présent pour les mêmes ID !!
    C'est quoi ce charabia ?

    Le order sert à trier. Que vient faire le status la dedans ?
    D'après ce que j'ai pu comprendre, vous sélectionnez trop de lignes, c'est--à-dire des lignes ayant le status à 8 (ce que vous cherchez à faire), mais d'autres lignes aussi ayant un status différent de 8.
    A priori, votre sélection est fausse et de surcroît le résultat attendu aussi.

    Citation Envoyé par nassertom
    la seule et unique solution est plusieurs jointures sur la même table ce que l'auteur du poste avait lui même proposé.
    Comme nous n'avons pas l'énoncé du problème, nous ne pouvons pas nous prononcer sur la solution de l'auteur, ni sur la pertinence de votre remarque.

    Citation Envoyé par nassertom
    en fait je n'ai pas ouvert de poste j'ai simplement répondu à ce poste (lien en bas de mon message)
    Le lien ne fonctionne pas.

    Citation Envoyé par nassertom
    ou j'ai jugé que la réponse donnée etait fausse et mon message explicité pourquoi et donne la bonne réponse.
    Quel message ? Votre message qui est à l'origine de ce sujet ou bien d'un autre sujet dont nous n'avons pas le lien ?

    Pourquoi créer un nouveau sujet si cela se rapporte à un autre sujet ?

    Le titre de votre sujet : "le or ou le in() fonctionne mais non fiable !!" est sans rapport avec votre exemple car on retrouve ni le "in" ni le "or" dans votre exemple.
    Veuillez corriger ce titre afin d'être en conformité avec votre exemple.

    Sans plus d'explication de votre part, d'un exemple avec jeu d'essai, en gros, cette discussion est inutile.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  6. #6
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut je n'ai pas de mot
    visiblement ma réponse au sujet initial est fausse... la bonne blague. je vous met au défit d'y répondre via un in() ...

    ok, je ne vais pas monopoliser les ressources actives du forum sur ce poste que je n'ai pas créé et qui n'a pas d'objet

    J'ai simplement voulu bien faire en répondant à une question d'il y a 9ans qui pour moi et toute mon incompétence communique une réponse fausse depuis 9ans
    mais ...

    voila je ferme le topique.

  7. #7
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut le lien du poste initial ou j'avais répondu

  8. #8
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut
    pour rappel la question du topique initial était (je résume) :
    si je fais une jointure comment puis-je récupéré via une table de pivot toutes les lignes qui réponde à plusieurs condition sur un même champ

    tout le monde sait que si dans une requête je met pour un même champs un and avec deux valeur différent il ne renvoit rien
    ex: la solution donnée depuis 9ans que je dit fausse est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    A.ID in (1,2)
    ...
    having count(A.ID)>1
    car rien ne garantie que si il y a plusieurs ID ils soient tous égaux à 1 et 2, ils seront tous égaux à 1 ou 2

    et je propose de faire plusieurs jointure de la même table de type inner
    avec dans le where
    maintenant celui qui précise que ma réponse est fausse qu'il me le prouve.

    avec d'autre opérateur type ANY ou en noSql c'est possible mais ce n'est pas l'objet du sujet actuel.

    donc messieurs les experts un peu de respect envers les simples gens qui essai de contribuer à leur hauteur.

    Je suis amère et je m'en excuse.
    Bien à vous

  9. #9
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 947
    Points : 5 846
    Points
    5 846
    Par défaut
    La jointure multiple n'est pas la seule et unique solution, ni potentiellement la plus performante.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    select c.titre
      from RECETTES C
      join PIVOT_RECETTES_INGREDIENTS D
        on D.RECETTE_ID = C.ID
     where D.INGREDIENT_ID in (1, 99)
     group by c.titre
    having count(distinct D.INGREDIENT_ID) = 2  /* 2 ingrédients dans le IN => 2 ingrédients dans le HAVING */
    Le DISTINCT D.INGREDIENT_ID est nécessaire s'il n'y a pas de contrainte d'unicité sur le couple (D.RECETTE_ID, D.INGREDIENT_ID), sinon un count(*) est également correct.

  10. #10
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut le in() n'est pas une solution
    dans l'exemple que tu donnes

    ce n'est pas par ce que ton count donne 2 que les id sont forcément 1 et 2 pour chaque ligne cela pourrait être 1 et 3 puis pour un autre 2 et 5...

    le count va te dire que dans ta jointure celui qui a aumoins 1 ou 2 comme ID à également d'autre ID présent dans cette table mais rien ne garanti qu'il réponde au besoin du 1 et 2.

    Bien à toi.

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Bonjour,
    La requête donnée par skuatamad renvoie toutes les recettes qui ont parmi leurs ingrédients le 1 ET le 99 (peut importe les autres ingrédients).
    Et oui, la requête fonctionne parfaitement.
    Et non, elle ne renvoie pas les recettes qui ont le 1 OU le 99 mais pas les deux (peut importe les autres ingrédients).

    Et si tu veux pas le croire, voici comment elle fonctionne:
    1. Elle va chercher toutes les recettes qui ont parmi leurs ingrédient le 1 ET/OU le 99 (la jointure)
    2. Elle compte le nombre distinct d'Id d'ingrédient renvoyés (dont uniquement les Id 1 OU 99) (le count distinct)
    3. Elle ne garde que les recettes pour laquelle elle a trouvé les 2 ingrédients (le having)

    Donc:
    • si une recette contient les ingrédients 1,8 et 15, la requête ne va compter qu'un ingrédient (le 1), le having va donc "rejeter" la ligne
    • si une recette contient les ingrédients 1,99 (et pourquoi pas d'autres) la requête va compter 2 id distinct (le 1 et le 99), le having match, la recette est "gardée"
    • si une recette contient les ingrédients 1,1,99,99 (et pourquoi pas d'autres) la requête va compter 2 id distinct (le 1 et le 99), le having match, la recette est aussi "gardée"

    Le groupage se faisant par recette, peu importe que la recette A contienne l'ingrédient 1 et la recette B l'ingrédient 99. Si aucune des deux ne contient les 2 ingrédients, les 2 seront "rejetées" par la requête.

    Allez, pour vraiment pinailler, il faudrait grouper non par le nom de la recette (qui peut ne pas être unique) mais par son Id.

    Tatayo.

  12. #12
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut chez moi c'est pas pareille
    Bonjour,

    merci pour ces explications et le temps passé.

    voici pourquoi je ne pense pas que cela soit bon.

    ceci chez moi donne 143 rows
    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
    143 rows returned in 363ms from: select  distinct C.titre
    from RECETTES C
    --inner join PIVOT_RECETTES_INGREDIENTS as D1 on D1.RECETTE_ID=C.ID
    inner join PIVOT_RECETTES_INGREDIENTS as D2 on D2.RECETTE_ID=C.ID
    inner join PIVOT_RECETTES_INGREDIENTS as D3 on D3.RECETTE_ID=C.ID
    inner join PIVOT_RECETTES_INGREDIENTS as D4 on D4.RECETTE_ID=C.ID
    inner join PIVOT_RECETTES_INGREDIENTS as D5 on D5.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D6 on D6.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D7 on D7.RECETTE_ID=C.ID
    --inner join PIVOT_RECETTES_INGREDIENTS as D8 on D8.RECETTE_ID=C.ID
    where 1=1
    --and D1.INGREDIENT_ID = '1'
    and D2.INGREDIENT_ID = '99'
    and D3.INGREDIENT_ID = '112'
    and D4.INGREDIENT_ID = '146'
    and D5.INGREDIENT_ID = '171'
    --and D6.INGREDIENT_ID = '204'
    --and D7.INGREDIENT_ID = '273'
    --and D8.INGREDIENT_ID = '131'
    ceci donne 166 rows
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    166 rows returned in 452ms from: select C.titre
    from RECETTES C
    inner join PIVOT_RECETTES_INGREDIENTS as D1 on D1.RECETTE_ID=C.ID
    where 
    D1.INGREDIENT_ID in ('99','112', '146','171')
    group by c.titre
    having count(distinct D1.INGREDIENT_ID) = 4
    de ce fait j'ai le sentiment que le fonctionnement n'est pas celui décrit mais celui-là mais je peux me tromper :
    1 le where avec le in va chercher tous ce qui a un '99' ou un '112'. ou un ..
    2 le having count lui => compte combien d’ingrédient on été remonté par la requête par titre et ne prend que les titre qui en on 4 => et donc si un titre est associé à 4 ingrédients dont un de la liste du in alors il le prend.
    pire encore les titre qui aurait bien les 4 ingrédients recherché mais qui par mal chance en auraient d'autre alors il serai rejeté car son count serait sup à 4.

    ceci est ma vision mais je ne suis pas expert SQL.

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Citation Envoyé par nassertom Voir le message
    de ce fait j'ai le sentiment que le fonctionnement n'est pas celui décrit mais celui-là mais je peux me tromper :
    1 le where avec le in va chercher tous ce qui a un '99' ou un '112'. ou un ..
    2 le having count lui => compte combien d’ingrédient on été remonté par la requête par titre et ne prend que les titre qui en on 4 => et donc si un titre est associé à 4 ingrédients dont un de la liste du in alors il le prend.
    pire encore les titre qui aurait bien les 4 ingrédients recherché mais qui par mal chance en auraient d'autre alors il serai rejeté car son count serait sup à 4.

    ceci est ma vision mais je ne suis pas expert SQL.
    C'est là que tu te trompes. La requête ne renvoie que les ingrédients de la liste (le IN). Les autres sont ignorés. Donc peut importe les ingrédients qui ne sont pas dans la liste.
    D'ailleurs si tu remplace le 4 par un 5 dans le HAVING, la requête ne doit plus rien renvoyer.

    Pour en avoir le cœur net, c'est simple: que renvoie cette requête:
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    select recettes.*
    from recettes
    inner join PIVOT_RECETTES_INGREDIENTS as D1 on D1.RECETTE_ID=C.ID
    inner join (
    select C.titre
    from RECETTES C
    inner join PIVOT_RECETTES_INGREDIENTS as D1 on D1.RECETTE_ID=C.ID
    where 
    D1.INGREDIENT_ID in ('99','112', '146','171')
    group by c.titre
    having count(distinct D1.INGREDIENT_ID) = 4) as s on s.titre = recettes.titres
    On doit avoir toutes les recettes qui ont les 4 ingrédients avec leur liste d'ingrédients (y compris ce qui ne sont pas dans la liste). Mais toutes les recettes doivent avoir les 4 ingrédients.

    Mais comme je l'indiquais, il suffit que 2 recettes aient le même titre (il existe plusieurs recettes de crêpes ) pour que ça ne fonctionne plus. Pour moi il faut ajouter l'id de la recette (qui lui est forcément unique).

    Maintenant je ne comprends pas trop d'où vient la différence entre les deux requêtes, mais pour ça il nous faut un jeu d'essai.

    Tatayo.

  14. #14
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut mea culpa
    En remplaçant le label par l'ID j'ai bien le même résultat entre les jointures et le in + having distinct count...

    Merci pour votre acharnement qui m'aura permis de comprendre.

    J'accepte avec humilité mon avertissement

    Bravo à tous.

  15. #15
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    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 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Pour créer ou comprendre une requête un peu complexe, on peut la construire ou la découper par étape...

    La requête suivante sélectionne les titres des recettes qui ont des lignes dans la table pivot_recettes_ingredients :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    select c.titre
      from RECETTES C
      join PIVOT_RECETTES_INGREDIENTS D
        on D.RECETTE_ID = C.ID
    Comme on ne veut que les recettes qui ont les ingrédients d'identifiants 1 et 99, on ajoute la condition de restriction. La requête ci-dessous va donner les titres des recettes qui ont, parmi leurs ingrédients, au moins un des ingrédients de la liste du IN :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    select c.titre
      from RECETTES C
      join PIVOT_RECETTES_INGREDIENTS D
        on D.RECETTE_ID = C.ID
     where D.INGREDIENT_ID in (1, 99)
    Nota : Si une recette utilise les deux ingrédients, elle apparaitra deux fois dans les lignes de résultat de la requête.

    Mais comme on ne veut que les recettes qui ont les deux ingrédients, il ne faut conserver que les recettes présentes deux fois dans le résultat de la requête. Il faut donc compter les lignes par recette et ne conserver que les recettes dont le comptage est de 2, ce qui se fait avec le HAVING :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    select c.titre
      from RECETTES C
      join PIVOT_RECETTES_INGREDIENTS D
        on D.RECETTE_ID = C.ID
     where D.INGREDIENT_ID in (1, 99)
     group by c.titre
    having count(distinct D.INGREDIENT_ID) = 2  /* 2 ingrédients dans le IN => 2 ingrédients dans le HAVING */
    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 !

  16. #16
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 380
    Points : 19 062
    Points
    19 062
    Par défaut
    Salut Nassertom.

    Maintenant que nous avons le lien d'il y a neuf ans, nous pouvons analyser et donner une solution à ce problème.

    Voici une remarque pertinente de BUGBUG au sujet de son problème :
    Citation Envoyé par bugbug
    Je veux que mon script ressort un numéro id d'annonce si seulement il y a les 2 enregistrements (2 critères) dans la table contenu_type_annonce.
    Dans cet exemple mon dernier script devrait ressortir l'annonce N°1 et pas l'annonce N°2 car la N°2 n'as pas les 2 critères (contenu 2 et contenu 6)
    Et voici son mini jeu d'essai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    |----+---------+---------+
    | id | annonce | contenu |
    |----+---------+---------+
    |  1 |    1    |    2    |
    |  2 |    1    |    6    |
    |  3 |    2    |    6    |
    |----+---------+---------+
    Que je vais traduire par :
    Rechercher dans la table annonce, les lignes ayant une "annonce", avec au moins un contenu = 2 et au moins un contenu = 6.

    Pour répondre à votre question :
    Citation Envoyé par nassertom
    la solution donnée depuis 9 ans que je dit fausse est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    A.ID in (1,2)
    ...
    having count(A.ID)>1
    Oui, je confirme, cette solution est fausse (voir ma première requête dans l'exemple plus bas).

    Citation Envoyé par nassertom
    car rien ne garantie que si il y a plusieurs ID ils soient tous égaux à 1 et 2, ils seront tous égaux à 1 ou 2
    Rien n'indique que pour une annonce donnée, tous les contenus soient tous différents.
    Autrement dit, pour que cette solution fonctionne, pour une annonce donnée, il faut une et une seule ligne ayant contenu = 2 et il faut une et une seule ligne ayant contenu = 6.
    Or il semble que cela ne soit pas le cas, c'est-à-dire que l'on peut très bien avoir plusieurs fois contenu = 2 sans avoir nécessairement contenu = 6.

    Citation Envoyé par nassertom
    et je propose de faire plusieurs jointure de la même table de type inner
    Les jointures ne sont pas nécessaires, voire même, alourdissent la requête inutilement. D'ailleurs une remarque concernant bugbug :
    Citation Envoyé par bugbug
    Mon problème est donc résolu, mais gros hic c'est incroyablement lent avec seulement 2 inner join ...
    Il semble que bugbug n'a pas mis un index sur la colonne contenu, d'où son problème de performance.

    Je constate, en effet, que personne dans le lien, n'a donné la solution , ni d'ailleurs dans ce sujet.
    A vrai dire, il me semble que personne n'a bien compris l'énoncé du problème.

    Je reprends la solution avec un count et un group by, qui ne fonctionne pas (première requête), comme vous pouvez le voir avec mon jeu d'essai.
    La solution que je propose (seconde requête) est basée sur la clause "exists", ce qui évite de faire deux jointures, d'où une meilleure performance !
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    --------------
    SET AUTOCOMMIT = 0
    --------------
     
    --------------
    START TRANSACTION
    --------------
     
    --------------
    DROP DATABASE IF EXISTS `base`
    --------------
     
    --------------
    CREATE DATABASE IF NOT EXISTS `base`
            DEFAULT CHARACTER SET `latin1`
            DEFAULT COLLATE       `latin1_general_ci`
    --------------
     
    --------------
    DROP TABLE IF EXISTS test
    --------------
     
    --------------
    CREATE TABLE test
    ( `id`         integer unsigned not null auto_increment primary key,
      `annonce`    smallint         not null,
      `contenu`    smallint         not null,
       INDEX `idx` (`contenu`)
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    insert into `test` (`annonce`,`contenu`) values
      (1, 2),
      (2, 4),
      (1, 6),
      (3, 2),
      (3, 5),
      (3, 2)
    --------------
     
    --------------
    select * from test
    --------------
     
    +----+---------+---------+
    | id | annonce | contenu |
    +----+---------+---------+
    |  1 |       1 |       2 |
    |  2 |       2 |       4 |
    |  3 |       1 |       6 |
    |  4 |       3 |       2 |
    |  5 |       3 |       5 |
    |  6 |       3 |       2 |
    +----+---------+---------+
    --------------
    select    annonce,
              count(*) as nbre
        from  `test`
       where  contenu in (2,6)
    group by  annonce
      having  nbre >= 2
    --------------
     
    +---------+------+
    | annonce | nbre |
    +---------+------+
    |       1 |    2 |
    |       3 |    2 |
    +---------+------+
    --------------
    select  distinct annonce
      from  `test` as t1
    where exists (  select  1
                     from  `test` as t2
                    where  t2.annonce = t1.annonce
                      and  t2.contenu = 2
                 )
      and exists (  select  1
                     from  `test` as t2
                    where  t2.annonce = t1.annonce
                      and  t2.contenu = 6
                 )
    --------------
     
    +---------+
    | annonce |
    +---------+
    |       1 |
    +---------+
    --------------
    COMMIT
    --------------
     
    --------------
    SET AUTOCOMMIT = 0
    --------------
     
    Appuyez sur une touche pour continuer...
    La première requête donne annonce = 3 alors que nous n'avons pas de contenu = 6.
    La seconde requête fournit le bon résultat.

    Citation Envoyé par nassertom
    donc messieurs les experts un peu de respect envers les simples gens qui essai de contribuer à leur hauteur.
    Nous sommes respectueux, mais mettez-vous à notre place quand nous découvrons le sujet où il y a ni jeu d'essai, ni énoncé du problème ni la solution attendue.
    Vous nous donnez une requête et l'on doit se débrouiller avec.

    En espérant que ma solution réponde à votre attente.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  17. #17
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    15
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 15
    Points : 18
    Points
    18
    Par défaut merci
    Merci pour vos explications.

    Effectivement, il n'est pas évident de bien comprendre les questions posées aussi diverses et variées et plus ou moins bien formulées.

    Me concernant, j’étais tellement persuadé d'avoir raison et avec comme unique motivation de proposer une réponse fiable et non de poser une nouvelle question, que j'ai été aveuglé.

    De ce fait, cela ne m'a pas permis de comprendre de suite.

    La solution proposée et les explications sont très claires et cela est logique.
    -le where limite les lignes aux conditions du in()
    -le having permet d'appliquer l’agrégation de type count sur base du champ mis dans le groupe by
    -le distinct supprime les doublons
    -la condition du count permet elle de ne prendre que le nombre d'arguments positionnés dans le in

    c'est évident et simple, mais pour le comprendre il faut être disposé à entendre, ce qui n’était pas mon cas lors des premiers échanges et c'est grâce à votre résilience que je me suis dit "ils ont peut être raison"

    Bref, merci et désolé pour l'affect que j'ai pu glisser dans mes postes.

    Au plaisir

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [11gR2] Having sans Group by fonctionne mais le livre de l'exam dit non
    Par Ikebukuro dans le forum SQL
    Réponses: 6
    Dernier message: 18/03/2016, 13h57
  2. Un code Jquery qui fonctionne sous une page HTML mais non pas une page XHTML
    Par élève_ingénieur dans le forum Balisage (X)HTML et validation W3C
    Réponses: 11
    Dernier message: 10/07/2011, 00h34
  3. Javascript ? Qui fonctionne mais en fait non
    Par le.squal dans le forum Général JavaScript
    Réponses: 18
    Dernier message: 01/02/2009, 10h04
  4. TextCtrl.disable() fonctionne mais non-grisé
    Par kalimero dans le forum wxPython
    Réponses: 1
    Dernier message: 31/01/2008, 13h34
  5. [PHP-JS] Script fonctionnant PHP 4 mais non en PHP 5 ?
    Par hepcowl dans le forum Langage
    Réponses: 3
    Dernier message: 08/03/2007, 21h30

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