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 :

Problème pour écrire des requetes mysql complexes


Sujet :

Requêtes MySQL

  1. #1
    Futur Membre du Club
    Profil pro
    Webmaster
    Inscrit en
    Janvier 2007
    Messages
    11
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Janvier 2007
    Messages : 11
    Points : 5
    Points
    5
    Par défaut Problème pour écrire des requetes mysql complexes
    Bonsoir à tous,

    Je rencontre une vraie difficulté avec la rédaction de requetes mysql complexes.... Malgré mes recherches et lectures, aucun de mes essais n'aboutit... Donc, j'aurai 3 questions bien précises en fait, et qui sont liées car concernent la meme page :


    1°/ QUESTION GENERALE MYSQL :
    J'ai un tableau qui affiche diverses données. Je veux que l'utilisateur puisse cliquer sur le titre des colonnes, afin de trier les résultats selon le critère qu'il a choisi. Pour pouvoir faire ceci, est-ce que je dois n'avoir qu'une seule requete pour récupérer mes résultats ? Car à priori, je me dis que pour pouvoir appliquer un "ORDER BY" à tous les résultats, il faut qu'ils soient tous issus de la meme requete, non ?


    2°/ QUESTION SYNTAXE REQUETE MYSQL :
    (Il s'agit donc ici de la requete concernée par la question 1. Donc je pars à priori sur la contrainte que je suis obligée de récupérer TOUTES mes données dans 1 seule et même requete.)
    Je veux récupérer la liste de tous les membres de mon site, avec pour chacun, diverses infos réparties dans d'autres tables de la meme base de données. J'utilise donc ce type de requete :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    "SELECT b.userid, b.username, a.nb_pts, d.name, d.id  
    FROM (table1 AS a, table2 AS b,table3 AS c, table4 AS d) 
    WHERE b.userid = a.userid AND c.clanid = a.clanid 
      AND c.userid = a.userid AND d.id = a.clanid"
    Cependant, certains membres n'ont pas d'entrée dans la table1 ou dans la table4 par exmple. Et du coup, mysql les filtre, et ils ne sont pas pris en compte dans les résultats. Donc mon soucis, c'est que quand je lui indique ou récupérer quelles infos, il en fait des condition qui doivent etre remplies. Or je veux qu'il m'affiche aussi les membres qui renvoient des valeurs "null" pour certains champs... J'ai testé avec des LEFT JOIN, mais sans aucun succès... je suis noyée !!!


    3°/ QUESTION SYNTAXE REQUETE MYSQL :
    Pour finir, l'autre problème que je rencontre. Toujours avec le même protocole qu'au dessus, je voudrais en plus des différentes infos sur le membre, récupérer l'ip et la date de sa dernière connexion, qui sont stockés dans la table CONNEXIONS. Cela correspond donc à la requete suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    "SELECT ip, date 
    FROM connexions 
    WHERE userid='".$userid."' 
    ORDER BY date DESC 
    LIMIT 1"
    Cependant, toujours pareil : je voudrais récupérer cette info dans la même requete que pour les autres infos. Cependant, j'ai l'impression que le "ORDER BY date DESC LIMIT 1" -qui ne doit s'appliquer qu'à cette partie de la requete- va poser problème pour "intégrer" cette requete à une requete déjà complexe....


    J'ai essayé d'être la + claire dans mes explications, en tout cas dans la mesure du possible... Bien entendu, je suis toute disposée à donner + d'infos ou reformuler autrement ce qui ne serai pas clair, suffit de demander ! ;-)

    En tout cas merci d'avance à ceux qui pourront m'aider, car là je désespère , et je pense même à supprimer les fonctionnalités que je voulais sur ma page, ce qui pour moi constitue le constat d'échec le + cuisant...!

    Merci de disposer tes requêtes sur plusieurs lignes (comme je viens de le faire) afin de faciliter la lecture

  2. #2
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    1/ on n'applique pas un ORDER BY à un résultat. On place une clause ORDER BY dans une requête. Autrement dit, tu as une requête-type, avec une clause ORDER BY qui change.

    Supposons que tes titres de colonne soient comme ça :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <input type=submit name=ordre value=username>
    <input type=submit name=ordre value=nb_pts>
    ...

    Tu pourras ensuite construire ta page comme ça :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $sql = "SELECT... " ;
    if ($_POST['ordre']) $sql .= " ORDER BY $_POST[ordre] " ;

    2/ il faut effectivement utiliser des LEFT JOIN, mais ça ne suffit pas.... Par exemple, supposons que table4 soit facultative (donc à droite du LEFT JOIN), mais et que tu veuilles lui imposer la condition suivante :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    WHERE d.clanid <> 0
    Pour les lignes de a (table1) qui n'ont pas de correspondance dans d, d.clanid est NULL, et ne vérifie donc pas ta condition <> 0 (NULL ne vérifie aucune condition sauf IS NULL et <=> NULL).
    Il faut donc écrire :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    WHERE (d.clanid <> 0 OR d.clanid IS NULL)

    3/ tu as entièrement raison... commence par réécrire ta requête avec des LEFT JOIN et je te montrerai ensuite comment intégrer tes dernières IP et date.
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  3. #3
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    Sur le 1, il y a aussi la possibilité de ne pas recontacter la BDD et de trier la liste au niveau de l'application cliente (mais si c'est du web ce sera au prix de plus de mémoire par session).

  4. #4
    Futur Membre du Club
    Profil pro
    Webmaster
    Inscrit en
    Janvier 2007
    Messages
    11
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Janvier 2007
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    tout d'abord merci Antoun pour tes précieux éclaircissements

    1/ Pour ce qui est du tri des résultats, pas de soucis avec cette partie, merci. Sur ce point, je voulais jsute une confirmation du fait que, pour appliquer un ordre de tri à des résultats, ceux-ci doivent etre issus d'une seule et même requete, à qui on ajoutera la clause "ORDER BY" adéquate.

    2/ voici donc les essais que j'ai fait, avec le LEFT JOIN, en prenant en compte les précisions que tu m'as indiquées. Bon, je précise déjà que je n'ai pas réussi à atteindre mon objectif pour l'instant... MAIS je m'en suis approchée, donc c'est déjà un point positif. En gros, depuis ce matin j'ai fait des tonnes de tests, avec toujours le même schéma : la résolution d'un problème en entraine un autre....
    Voici la requete avec laquelle j'obtiens le résultat le + approchant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SELECT a.userid, a.username, d.name, d.id, c.nb_pts   
    FROM  (table_a AS a)
    LEFT JOIN (table_b AS b, table_c AS c, table_d AS d)
    ON  (b.userid = a.userid OR b.userid IS NULL)
    AND (d.id = b.clanid OR b.clanid IS NULL)
    AND (c.clanid = b.clanid OR c.clanid IS NULL)
    AND (c.userid = a.userid OR c.userid IS NULL)
    mais avec cette requete, il demeure un problème : pour les membres qui n'ont pas de points enregistrés (= pas d'entrées dans la table_c), il ne récupère ni d.name ni d.id, comme s'ils étaient vides...


    J'ai réussi à résoudre ce problème avec cette requete-là, mais ça a créé un nouveau problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT a.userid, a.username, d.name, d.id, c.nb_pts   
    FROM  (table_a AS a, table_d AS d)
    LEFT JOIN (table_b AS b, table_c AS c)
    ON  (b.userid = a.userid OR b.userid IS NULL)
    AND (c.clanid = b.clanid OR c.clanid IS NULL)
    AND (c.userid = a.userid OR c.userid IS NULL)
    WHERE (d.id = b.clanid OR d.id IS NULL OR b.clanid IS NULL)
    GROUP BY userid
    Là, pour les points c'est ok : meme quand il n'y en a pas, ça m'affiche bien le d.name et d.id. MAIS, cette fois, pour les membres qui n'ont pas d'entrées dans la table_d, au lieu de ne rien afficher, il affiche malgré tout une valeur (donc erronée) pour d.name et d.id, qui correspondent à la première entrée de table_d...


    Bref, je sens que les choses se précisent, que je m'approche de THE requete, mais je sens bien également qu'il doit y avoir des choses qui m'échappent encore, sinon au bout de 5h intensives de tests divers et variés, j'aurais du trouvé la solution, non ?

    (Pour le point 3, je laisse effectivement de coté pour l'instant. On verra dans un second temps, ou peut etre même je trouverai la solution toute seule... Ben ouais, faut rester optimiste malgré tout ! )

    Merci d'avance pour l'aide

  5. #5
    Membre éprouvé
    Avatar de Sivrît
    Profil pro
    Inscrit en
    Février 2006
    Messages
    953
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2006
    Messages : 953
    Points : 1 249
    Points
    1 249
    Par défaut
    Je suggère quelquechose dans le genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT a.userid, a.username, d.name, d.id, c.nb_pts   
    FROM table_a AS a LEFT JOIN table_b AS b ON b.userid = a.userid
                      LEFT JOIN table_d AS d ON d.id = b.clanid
                      LEFT JOIN table_c AS c ON c.userid = a.userid AND (b.clanid IS NULL OR c.clanid = b.clanid)
    'table_a' & co, c'est pour masquer les noms des tables sur le forum ? Parce que là c'est plutôt imbuvable et ça n'aide pas à voir l'enchainement des tables (dont dépend l'ordre des jointures et la nécessité du 'LEFT').

    Pour la dernière jointure j'y vais un peu au petit bonheur la chance. S'il y a pour certains joueurs des points dans des clans ET en solo ça va être problématique, de même s'il y a des points dans des clans où ils ne sont plus car on a alors deux listes qui ne correspondent pas. Dans ce cas il faudra je pense décider de lister en priorité les points ou les clans.

  6. #6
    Futur Membre du Club
    Profil pro
    Webmaster
    Inscrit en
    Janvier 2007
    Messages
    11
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Janvier 2007
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    génial, merci Sivrît !! car ça marche comme je le souhaitais !!!!
    Ainsi j'ai capté ce qui m'échappait dans le principe... : c'était d'appliquer les clauses ON à chaque LEFT JOIN, au lieu de mettre tous les LEFT JOIN ensemble, et ensuite toutes les clauses ON comme je le faisais.

    Sinon, pour répondre à ta question, les "table_a" ect.. c'était plutot pour essayer de rendre ma requete simple et claire, mais apprement c'était pas le bon choix...
    Donc voici ma requete avec les noms de tables réels :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT a.userid, a.username, d.name, d.id, c.nb_pts   
    FROM membres AS a 
    LEFT JOIN clans_att AS b ON b.userid = a.userid
    LEFT JOIN clans AS d ON d.id = b.clanid
    LEFT JOIN clans_pts AS c ON c.userid = a.userid AND (b.clanid IS NULL OR c.clanid = b.clanid)
    Mais vu que ce problème semble être résolu, je ne pense pas que ça soit nécessaire que je donne + d'explications sur mes tables, leur contenu et leur relation. Tu as bien capté les choses telles qu'elles sont, avec les bonnes contraintes ect, c'est super ! Enfin si besoin, pas de soucis, je donne + de précisions.


    On va donc pouvoir passer au second problème, (évoqué en point 3 dans mon 1er post). En plus de ces infos, je dois récupérer pour chaque membre, dans la table connexions, la date et l'adresse IP de la dernière connexion, ce qui correspond tout bêtement à cette requete :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT ip, date 
    FROM connexions 
    WHERE userid='".$userid."' 
    ORDER BY date DESC 
    LIMIT 1
    Cependant, j'ai besoin de récupérer ces données via la même requete que j'utilise déjà pour récupérer les autres données (au-dessus). Donc je me demandais comment réussir à "intégrer" cette requete dans ma requete initiale (sachant que $userid correspondra au champ a.userid). Là je suppose qu'il s'agit d'une histoire d'imbrication de requêtes....

  7. #7
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    ça devrait donc faire qqch comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    SELECT a.userid, a.username, d.name, d.id, c.nb_pts,  co.ip, co.date
    FROM membres AS a 
      INNER JOIN connexions  AS co 
        ON a.userid = co.userid 
          AND co.date =  (SELECT MAX(co2.date) FROM connexions AS co2 WHERE co2.userid= co.userid )
    
      LEFT JOIN clans_att AS b ON b.userid = a.userid 
      LEFT JOIN clans AS d ON d.id = b.clanid 
      LEFT JOIN clans_pts AS c ON c.userid = a.userid AND (b.clanid IS NULL OR c.clanid = b.clanid)
    Techniquement parlant, (SELECT MAX(co2.date) FROM connexions AS co2 WHERE co2.userid= co.userid ) est une sous-requête scalaire (elle ne renvoie qu'une valeur et peut donc s'utiliser à la place d'une valeur simple) et corrélée (elle inclut une condition par rapport à la requête principale).
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

  8. #8
    Futur Membre du Club
    Profil pro
    Webmaster
    Inscrit en
    Janvier 2007
    Messages
    11
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Webmaster

    Informations forums :
    Inscription : Janvier 2007
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Antoun, tu es trop fort !

    La solution que tu as suggérée correspond parfaitement à mon cahier des charges, je l'ai un peu adaptée et c'est vraiment parfait. Tu n'imagines pas l'utilité pour moi de ce que j'ai appris via ce post ! Donc vraiment MERCI !!!!! Je rêve d'avoir ta maitrise du sujet mysql, car ça fait gagner un temps fou dans l'intégration, de pouvoir obtenir exactement ce que l'on souhaite, précisemment.... Mais petit à petit...l'oiseau fait son nid ;-)

    Sinon, pour ma culture personnelle, j'aurai bien aimé en savoir un peu plus sur ce qu'évoquait Sivrî (concernant l'obligation ou pas d'avoir une requete unique pour pouvoir appliquer un ordre de classement sur tous les résultats) :
    Citation Envoyé par Sivrî
    Sur le 1, il y a aussi la possibilité de ne pas recontacter la BDD et de trier la liste au niveau de l'application cliente (mais si c'est du web ce sera au prix de plus de mémoire par session).

  9. #9
    Rédacteur/Modérateur

    Avatar de Antoun
    Homme Profil pro
    Architecte décisionnel
    Inscrit en
    Octobre 2006
    Messages
    6 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Architecte décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2006
    Messages : 6 281
    Points : 11 737
    Points
    11 737
    Par défaut
    la requête "le + récent de" est un grand classique... qui fait tj son effet !

    pour l'idée de Sivrît, j'ai effectivement déjà construit un truc comme ça en JavaScript + DOM. L'idée était de détruire et reconstruire intégralement le tableau de résultats sur un clic de bouton ; ça suppose bien sûr que tu n'aies pas trop de lignes...
    Antoun
    Expert Essbase, BO, SQL

    La bible d'Essbase, 2ème édition

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

Discussions similaires

  1. requete mysql complexe pour dessiner une courbe lineaire
    Par fou-jea dans le forum Requêtes
    Réponses: 1
    Dernier message: 07/09/2012, 14h50
  2. [MySQL] Comment utiliser MySQL Worbench pour faire des requetes affichage
    Par Debutant10 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 29/12/2011, 22h38
  3. Problème pour écrire des messages
    Par troumad dans le forum La taverne du Club : Humour et divers
    Réponses: 1
    Dernier message: 07/01/2010, 13h55
  4. [fileupload] problème pour parser la requete
    Par jaimepasteevy dans le forum Struts 1
    Réponses: 12
    Dernier message: 24/04/2008, 12h02
  5. Problème pour rentrer des données dans MySQL
    Par Sandara dans le forum Requêtes
    Réponses: 8
    Dernier message: 06/06/2006, 10h59

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