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 :

LIMIT calcul mal avec des JOIN


Sujet :

Requêtes MySQL

  1. #1
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut LIMIT calcul mal avec des JOIN
    Voici un copier-coller d'une discution sur un autre forum qui résume très bien mon problème mais qui n'à recu aucune solution. (Je donnerais bien le lien mais ca serait de la pub donc je copie-colle)

    KosMos
    Posté le: 28 Déc 2004, 12:58 Sujet du message: Mysql - Limit et left join Bonjours à tous, me voila confronté à un problème assez particulier... :

    Je dispose d'une table articles, contenant des... articles et composé des champs suivants :

    id | type | title | resume | text | date | author_id

    Ainsi que d'une table comments contenant les commentaires des dits articles et composé des champs suivants :

    id | article_id | name |text | date

    Je cherche à récuperer les 8 premiers articles de la tables ainsi que les commentaires correspondants à chaque articles. Voici donc ma requette mysql :

    SELECT a.id,a.title,a.resume,a.date,
    c.id AS c_id,c.name AS c_name,c.text AS c_text,c.date AS c_date
    FROM articles AS a
    LEFT JOIN comments AS c ON c.article_id=a.id
    ORDER BY a.id DESC
    LIMIT 8

    Cependant, le LIMIT s'applique sur le nombre de champs retournés, et non sur le nombre d'article. Si un premier article comporte 5 commentaires, et le suivant 3, la requette ne retournera que ces deux la.
    Impossible de faire un GROUP BY a.id, car je n'aurais alors accès qu'au premier commentaire de chaque article.
    Impossible de se débrouiller avec un GROUP BY c.id, puisque si deux articles ne comportent pas de commentaires, ils seront groupés ensemble !

    Je suis complètement dérouté face à se problème, si quelqu'un pouvais m'éclairer, je lui en serait très reconaissant.
    je comprend le fonctionnement du limit, mais comment faire pour réellement limiter les messages 'normalement' ?

    Dans mon cas, les messages ont des destinataires.
    Il peut y avoir 1 destinataire, 10, 134, etc... infini quoi.

    Donc si je veux afficher 100 messages sur ma page, il m'affichera seulement le ou les message envoyé aux premier 100 destinataires.

    Donc au lieu d'avoir 100 messages, je me retrouve avec 10 messages de 10 destinataires chacun par exemple.

    Les destinataires étant totalement aléatoire, je ne peux pas placer un facteur de correction sur les chiffres du limit .. :-\

  2. #2
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    Salut !

    Si tu as MySQL >= 4.1, tu pourras faire des sous-requêtes, et donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT a.id,a.title,a.resume,a.date,
    c.id AS c_id,c.name AS c_name,c.text AS c_text,c.date AS c_date
    FROM articles AS a
    LEFT JOIN comments AS c ON c.article_id=a.id
    ORDER BY a.id DESC
    WHERE a.id IN (SELECT a2.id FROM articles a2 ORDER BY a2.id DESC LIMIT 8)
    ce qui devrait résoudre, je pense, ton problème

    Si tu n'as que MySQL < 4.1... il va falloir que tu fasses la coupure à la main

  3. #3
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Dans mon cas la requêtes est:

    SELECT he.msg, he.date, he.id AS hid, he.type, pc.nom, ft2.fromto, ft2.persoid, ft2.description, p.sexe, p.imgurl, s.expiration
    FROM he_fromto AS ft
    LEFT JOIN he_fromto AS ft2 ON ( ft2.msgid = ft.msgid )
    LEFT JOIN he AS he ON ( ft.msgid = he.id )
    LEFT JOIN perso_connu AS pc ON ( pc.persoid = ft.persoid AND pc.nomid = ft2.persoid )
    LEFT JOIN perso AS p ON ( p.id = ft.persoid )
    LEFT JOIN session AS s ON ( s.user = p.user )
    WHERE ft.`show`=1 AND ft.persoid=109
    GROUP BY hid,ft2.fromto,ft2.persoid
    ORDER BY `date` DESC, hid ASC , ft.fromto ASC , pc.nom ASC
    LIMIT 0,100;
    Edit, les messages sont dans "he". he_fromto contiend la liste des destinataires, c'est cette jointure qui pose problème car elle multiplie les lignes.

    C'est une bonne idée de passer tout ca en sous-requêtes ? Je risque pas de perdre des performances ? Car déjà c'est une requête assez monstre.


    Bon, j'ai tenté la modification suivante:
    SELECT he.msg, he.date, he.id AS hid, he.type, pc.nom, ft.fromto, ft.persoid, ft.description, p.sexe, p.imgurl, s.expiration
    FROM cc3_he AS he
    LEFT JOIN cc3_he_fromto AS ft ON ( ft.msgid = he.id )
    LEFT JOIN cc3_perso_connu AS pc ON ( pc.persoid =189
    AND pc.nomid = ft.persoid )
    LEFT JOIN cc3_perso AS p ON ( p.id = ft.persoid )
    LEFT JOIN cc3_session AS s ON ( s.user = p.user )
    WHERE he.id
    IN ([X d'erreur de PHPMyAdmin]
    SELECT msgid
    FROM cc3_fromto
    WHERE persoid =189
    AND ft.`show` =1
    LIMIT 0 , 100
    )
    GROUP BY hid, ft.fromto, ft.persoid
    ORDER BY `date` DESC , hid ASC , ft.fromto ASC , pc.nom ASC
    et PHPMyAdmin me sort l'erreur suivante:
    #1235 -


    MySQL 4.1.18
    Vous êtes certain qu'on peux mettre des limit dns les sous-requêtes ?

  4. #4
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    essaie ceci (et ajoute le texte de l'erreur la prochaine fois )
    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 he.msg, he.date, he.id AS hid, he.type, pc.nom, ft.fromto, ft.persoid, ft.description, p.sexe, p.imgurl, s.expiration
    FROM cc3_he AS he
    LEFT JOIN cc3_he_fromto AS ft ON ( ft.msgid = he.id )
    LEFT JOIN cc3_perso_connu AS pc ON ( pc.nomid = ft.persoid )
    LEFT JOIN cc3_perso AS p ON ( p.id = ft.persoid )
    LEFT JOIN cc3_session AS s ON ( s.user = p.user )
    WHERE he.id
    IN (
    SELECT sstbl.msgid
    FROM cc3_fromto sstbl
    WHERE sstbl.`show` = 1 AND sstbl.persoid = 189
    LIMIT 0 , 100
    )
    ORDER BY `date` DESC , hid ASC , ft.fromto ASC , pc.nom ASC
    il n'y a pas de problème a faire une sous-requête, pour obtenir le resultat que tu veux... en plus les requêtes ne sont pas corréllées (quelque soit la ligne analysée par la requête principale, le résultat de la sous-requête ne changera pas) donc il ne devrait pas y avoir de très gros ralentissements...

    mais je n'ai pas compris pourquoi faire un GROUP BY ?
    ni pourquoi tu as modifié le WHERE pour le déplacer de cette façon ?
    de même que les changements de nom de table (un coup avec cc3 un coup sans, etc...)
    il serait bon d'avoir les structures de tes tables

  5. #5
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Ha ouais, désolé.

    cc3_ est le préfixe des tables. Dans mon code php, j'ai supprimé la partie " . DB_PREFIX . " la première fois et la deuxiéme requête était un copier coller d'un essaie sous PHPMyAdmin



    Pour l'erreur j'ai tout mis, il n'y a QUE le # qui semble signifier une incompatibilité avec la version de MySQL. ( De php_info: Client API version 4.1.18 , confirmé pas PHPMyAdmin)

    Pour le WHERE, je sais pas trop, c'était qu'un essaie, donc qu'une erreur ... Le Group By j'avais pas pensé à le retirer.

    C'est vrai qu'avec tout ca en moins, si ca pouvait fonctionner je pense que ca serait plus optimisé...


    Pour les tables, il suffit de ce concentrer sur:
    cc3_he , qui contiend la liste des messages
    cc3_he_fromto, qui contiend l'envoyeur (champ fromto = from) et les destinataire (champ fromto=to) d'un message (champ msgid)

    ensuite:
    cc3_perso_connu c'est pour savoir si le destinataire (ou l'envoyeur) est 'connu' du joueur (s'il à été renommé, sinon il sera affiché en tant qu'inconnu)
    cc3_session c'est pour les session, ca permet de savoir si le joueur est online ou pas et s'il est actif ou pas.
    cc3_perso c'est la table des personnages, qui dans ce cas-ci fait le lien entre le message (qui utilise l'id du personnage) et la session (qui utilise le nom d'utilisateur)

    Merci !
    Images attachées Images attachées  

  6. #6
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    j'ai retrouvé l'erreur lol (dans la doc de MySQL)
    Error: 1235 SQLSTATE: 42000 (ER_NOT_SUPPORTED_YET)

    Message: This version of MySQL doesn't yet support '%s'
    donc ta version de MySQL doit être < 4.1 (la version de MySQL, pas l'API client !!!)

    Normalement sur la page d'acceuil de pMA (dernière version) tu as en gros un truc du style :

    MySQL - 4.1.19-log phpMyAdmin - 2.8.1
    (en vraiment gros )

    c'est cette version là qui est importante ou alors en cherchant la variable version dans les variables du serveur

  7. #7
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    MySQL - 4.1.18-standard-log
    • Version du protocole: 10
    phpMyAdmin - 2.8.1
    • Version du client MySQL: 4.1.18
    • Extensions PHP utilisées: mysql


    Mais ceci dit j'ai des problème de serveur en ce moment, donc ca pourait expliquer bien des trucs...


    Edit: problème de serveur réglé, cette fois j'ai l'erreur complète:
    #1235 - This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

  8. #8
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Avis aux intéressés:


    4.1 does suport subqueries, but the restriction on LIMIT was lifted in recent versions of 5.0 and 5.1. i don't think lifting that restriction in 4.1 is in the works.
    ^^ bon, ca parlais d'un autre problème mais en gros ca veux dire que les LIMIT dans les sous-requête c'est MySQL 5 et plus..

  9. #9
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    J'ai installé MySQL 5.0.22 et la requête de Swoog me retourne:
    Erreur #1235: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

    Comment faire alors ? J'ai essayé avec un = à la place du IN, mais ca me dit que ca retourne plus d'une ligne (normal..)

  10. #10
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    exact, j'ai oublié que MySQL ne supportais pas LIMIT dans les sous-requêtes, enlève-le, de toutes façons, il ne sert à rien...

  11. #11
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Heu oui il sert !
    Il sert à délimiter les pages.

    Contexte:
    Cette mega requête sert à afficher une liste de messages sur une page avec des informations connexes (destinataires, etc)

    La page 1 affiche les message de 1 à 100
    La page 2 affiche les messages de 101 à 200

    etc.. c'est à ca que le limit sert.
    Pour le moment j'ai fait deux requête la première créer une liste d'id et cette liste est placé dans le IN de la seconde requête...

  12. #12
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    dans ce cas, il faut qu'il soit dans la requête principale, et pas dans la sous-requête

  13. #13
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Impossible puisque la requête retourne aussi la liste des destinataire (et possiblement DES envoyeurs).

    Donc un LIMIT ne limite pas le nombre de message, mais le nombre d'envoyeur+récepteurs.

  14. #14
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    dans ce cas, ta requête est mal formée, modifie-là

    dans tous les cas, MySQL interdit pour le moment le LIMIT dans les sous-requête, dsl

  15. #15
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Citation Envoyé par Swoög
    dans ce cas, ta requête est mal formée, modifie-là

  16. #16
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    j'ai mal formulé :

    La sémantique de ta requête telle qu'elle est actuellement exprimée n'est pas compatible avec la syntaxe proposée par MySQL, il te faut donc la modifier pour qu'il puisse y avoir correspondance entre les deux ^^

    c'est moins choquant ?

  17. #17
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Ca n'était pas choquant la première fois, je vois juste pas trop comment faire.

    Pour simplifier au maximum la problématique:


    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
     
     
    Note: dans cette exemple nous somme le membre 189.
     
    Table: he_FromTo:
     
    msgid | fromto  | userid | show
    ------|---------|--------|-------
    1     | from    | 189    | 1
    1     | to      | 12     | 1
    1     | to      | 14     | 0
    1     | to      | 162    | 1
    2     | from    | 112    | 1
    2     | to      | 12     | 0
    2     | to      | 189    | 1
    2     | to      | 162    | 1
    3     | from    | 112    | 1
    3     | to      | 12     | 0
    3     | to      | 189    | 0
    3     | to      | 162    | 1
     
     
    Table: he (les messages):
     
    id    |  date    | msg   
    ------|----------|----------
    1     | 564273   | Bonjour!
    2     | 345624   | Salut...
    3     | 436456   | Ca va?
     
     
     
    Le résultat final doit afficher quelque chose comme:
     
    #1
    De: 189
    A:  12, 14, 162
    Msg: Bonjour!
     
    [Si le #3 n'était pas effacé, il serait affiché ici]
     
    #2:
    De: 112
    A: 12, 189, 62
    Msg: Salut...

    Le nombre de message dans la boite de message est: 2 et non pas 8.

    J'essaie de créer une requête qui peu aller chercher toutes les informations sans devoir faire une requête dans une boucle.

    J'y suis présentement parvenu avec 2 requêtes, mais j'aimerais savoir comment faire en une seule... ou comment modifier ma sémentique vu que cette requête est LA plus importante du moteur du site en question et qu'elle sera TRÈS fortement utilisée.

  18. #18
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    effectivement... là, je ne vois pas trop non plus comment faire...

    Je pense, que pour le moment, le plus simple et plus efficace et de faire deux requêtes séparées : d'abord la sous-requête avec le limite de pagination etc...

    puis la seconde... ça évite d'avoir à faire une requête pour chaque message, je pense que c'est le mieux... jusqu'à ce que MySQL autorise les LIMIT dans les sous-requêtes...

  19. #19
    Membre confirmé
    Avatar de FMaz
    Inscrit en
    Mars 2005
    Messages
    643
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 643
    Points : 640
    Points
    640
    Par défaut
    Et si j'envisage de changer la structure de mes tables, tu aurais une idée ?

  20. #20
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    non, pas vraiment... je ne vois pas trop comment ça pourrait se faire...

    c'est la liaision 1<->1..n des destinataires qui pose problème en fait...

Discussions similaires

  1. effectuer calculs mathematiques avec des données sql
    Par manutergnier dans le forum Requêtes
    Réponses: 5
    Dernier message: 22/05/2008, 10h38
  2. Problème avec des JOIN
    Par fredonouille dans le forum SQL
    Réponses: 2
    Dernier message: 26/02/2008, 18h50
  3. Problème calcul arithmétique avec des float
    Par tioneb369 dans le forum Langage
    Réponses: 4
    Dernier message: 18/09/2007, 14h35
  4. calculs mathématiques avec des "racines)
    Par emmanuel4945 dans le forum Access
    Réponses: 1
    Dernier message: 30/01/2006, 21h40
  5. Réponses: 2
    Dernier message: 28/09/2005, 17h08

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