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 :

Utiliser MAX() en condition dans un LEFT JOIN


Sujet :

Langage SQL

  1. #1
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2008
    Messages
    504
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 504
    Points : 470
    Points
    470
    Par défaut Utiliser MAX() en condition dans un LEFT JOIN
    Bonjour,

    J'ai 2 tables, qu'on appelera Joueur et Niveau, avec niveau qui contient une clef étrangère sur Joueur.

    Joueur (id int(11), nom varchar(32))
    Niveau (#joueur int(11), niveau int(11), points int(11))
    Admettons maintenant que je veuille récupérer tous les joueurs ayant atteint un certain niveau (ni plus ni moins)...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select * from joueur where (select max(niveau.niveau) from niveau where niveau.joueur = joueur.id group by niveau.joueur) = 10
    Ce qui devrait fonctionner, mais ne me parait pas terrible car :

    1 - il doit etre possible de faire ça avec un left join
    2 - je ne récupère pas le contenu de la variable point correspondant à l'enregistrement niveau = 10

    Aussi, existe une méthode plus avantageuse comblant ces 2 lacunes ?

  2. #2
    Membre émérite Avatar de lola06
    Femme Profil pro
    Consultante en Business Intelligence
    Inscrit en
    Avril 2007
    Messages
    1 316
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultante en Business Intelligence
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 316
    Points : 2 520
    Points
    2 520
    Par défaut
    Normalement ceci devrait faire l'affaire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT *
     
    FROM joueur
     
       LEFT OUTER JOIN (
          SELECT max(niveau) niv, joueur
          FROM niveau
          GROUP BY joueur
       ) niveau
       ON niveau.joueur = joueur.id
     
    WHERE niv = 10
    Dans tous les cas le GROUP BY n'est pas utile dans ta requête.
    ~ Lola ~

  3. #3
    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
    Niveau (#joueur int(11), niveau int(11), points int(11))
    D'après cette structure, chaque joueur n'apparaît qu'une seule fois dans la table.
    => Il n'y a qu'un niveau par joueur.

    Admettons maintenant que je veuille récupérer tous les joueurs ayant atteint un certain niveau (ni plus ni moins)...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM joueur WHERE (SELECT max(niveau.niveau) FROM niveau WHERE niveau.joueur = joueur.id GROUP BY niveau.joueur) = 10
    D'après cette requête, si j'ai bien compris, tu veux tous les joueurs de niveau 10.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT j.id, j.nom,
    	n.points
    FROM niveau n
    INNER JOIN joueur j ON j.id = n.joueur
    WHERE n.niveau = 10
    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 !

  4. #4
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2008
    Messages
    504
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 504
    Points : 470
    Points
    470
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    D'après cette structure, chaque joueur n'apparaît qu'une seule fois dans la table.
    => Il n'y a qu'un niveau par joueur.
    Bon, j'ai des lundi plus difficiles que d'autre et celui là est particulièrement violent pour moi, mais à moins de l'avoir encore gravement sous estimé, je dirais que c'est une mauvaise lecture de l'énoncé !

    il peut y avoir autant de niveau par joueur que l'on veut, puisque #joueur signifie qu'il s'agit d'une clef étrangère, non d'une clé primaire ni d'une clef unique...

    En tout état de cause, ce que je donne ici est un exemple qui ne correspond pas à la réalité à laquelle je suis actuellement confronté (j'ai inventé les tables à la volée pour l'exemple). Je cherche en effet à comprendre une philosophie, et je cherche bien à savoir quelle est la bonne méthode à utiliser si il y a un nombre indéterminé d'enregistrement "niveau" par enregistrement "joueurs" (donc une relation 0, n - 1, 1).

    En attendant, j'ai mis en pratique la solution de lola06 (que je remercie) qui fonctionne bien. Par contre, en terme de performance, est-ce la meilleure solution où y a t-il moyen d'optimiser ?

  5. #5
    Membre chevronné
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Points : 1 806
    Points
    1 806
    Par défaut
    Citation Envoyé par comode Voir le message
    Ce qui devrait fonctionner, mais ne me parait pas terrible car :

    1 - il doit etre possible de faire ça avec un left join
    Non, pas avec cette structure. Il va bien falloir pour chaque joueur avoir une vue d'ensemble des niveaux atteints !

    2 - je ne récupère pas le contenu de la variable point correspondant à l'enregistrement niveau = 10
    Ça peut se faire plus ou moins simplement suivant le SGBD.

  6. #6
    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
    il peut y avoir autant de niveau par joueur que l'on veut, puisque #joueur signifie qu'il s'agit d'une clef étrangère, non d'une clé primaire ni d'une clef unique...
    Tu veux donc les joueurs dont le niveau maxi atteint est le niveau 10 ?

    Donc on commence par cherche le niveau max atteint par chaque joueur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT joueur, MAX(niveau) AS niveau_max
    FROM niveau
    GROUP BY joueur
    Ensuite on récupère les autres données en faisant une jointure sur cette 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
    SELECT j.id, j.nom,
    	n.points
    FROM niveau n
    INNER JOIN
    (
    	SELECT joueur, MAX(niveau) AS niveau_max
    	FROM niveau
    	GROUP BY joueur
    ) tmp
    	ON tmp.joueur = n.joueur
    	AND tmp.niveau_max = n.niveau
    INNER JOIN joueur j ON j.id = n.joueur
    WHERE n.niveau = 10
    C'est bon ou il y a encore un truc que je n'ai pas compris ?
    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 !

  7. #7
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2008
    Messages
    504
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2008
    Messages : 504
    Points : 470
    Points
    470
    Par défaut
    Non c'est bon, j'ai pigé la philosophie qui permet d' "exploiter une jointure contenant les résultats d'un select comme une sorte de "table" réutilisable dans la requête principale" !

    Je me demandais également s'il était possible de faire disparaître le select imbriqué, mais il semble que non...

    Merci et résolu !

  8. #8
    Membre habitué
    Inscrit en
    Septembre 2010
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 82
    Points : 140
    Points
    140
    Par défaut
    Citation Envoyé par comode Voir le message
    Je me demandais également s'il était possible de faire disparaître le select imbriqué, mais il semble que non...
    Perso, pour des raisons de lisibilité, j'utilise des CTE (common table expressions). Et en plus c'est un standard ANSI

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

Discussions similaires

  1. [MySQL] Select dans un Left Join et champ inconnu
    Par wenijah dans le forum PHP & Base de données
    Réponses: 0
    Dernier message: 13/04/2012, 12h19
  2. "fetch first 1 rows only" dans un "Left Join"
    Par nico.exe dans le forum DB2
    Réponses: 5
    Dernier message: 02/04/2012, 16h25
  3. Conditions : dans le INNER JOIN ou le WHERE ?
    Par Khleo dans le forum Langage SQL
    Réponses: 2
    Dernier message: 28/12/2010, 21h50
  4. Requete SQL - count dans un left join
    Par JbWillGetYou dans le forum Langage SQL
    Réponses: 7
    Dernier message: 02/06/2010, 01h07
  5. count() dans *plusieurs* LEFT JOIN
    Par silver_dragoon dans le forum Langage SQL
    Réponses: 2
    Dernier message: 28/06/2004, 17h20

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