web-dev-qa-db-fra.com

MySQL ORDER BY plusieurs colonnes ASC et DESC

J'ai 2 tables MYSQL, tilisateurs et scores. Détail:

  • tableau des utilisateurs:

enter image description here

  • tableau des scores:

enter image description here

Mon intention est d’obtenir 20 listes d’utilisateurs qui ont point trier les champs DESC (décroissant) combine avg_time trier les champs ASC (ascendant). J'utilise la requête:

SELECT users.username, scores.point, scores.avg_time
FROM scores, users
WHERE scores.user_id = users.id
GROUP BY users.username
ORDER BY scores.point DESC, scores.avg_time
LIMIT 0, 20

Le résultat est:

enter image description here

Le résultat est faux car la première ligne est exactement le point = 100 et avg_time = 60.

Le résultat souhaité est:

username    point    avg_time
demo123      100        60
demo123456   100       100
demo         90        120

J'ai essayé plusieurs fois avec différentes requêtes, mais le résultat est toujours faux. Pourriez-vous me donner des solutions?

Merci d'avance!

30
Tan Viet

Ok, je pense que je comprends ce que vous voulez maintenant, et laissez-moi préciser pour confirmer avant la requête. Vous voulez 1 enregistrement pour chaque utilisateur. Pour chaque utilisateur, vous voulez enregistrer son score de points BEST POINTS. Parmi les meilleurs points par utilisateur, vous voulez celui avec le meilleur temps moyen. Une fois que vous avez défini les "meilleures" valeurs des utilisateurs, vous souhaitez que les résultats finaux soient triés avec les meilleurs points en premier ... Presque comme le classement d'une compétition.

Alors maintenant, la requête. Si la déclaration ci-dessus est exacte, vous devez commencer par obtenir le meilleur point/temps moyen par personne et attribuer un "classement" à cette entrée. Cela se fait facilement en utilisant MySQL @ variables. Ensuite, ajoutez simplement une clause HAVING pour ne conserver que les enregistrements classés 1 pour chaque personne. Enfin, appliquez l'ordre des meilleurs points et du temps moyen le plus court.

select
      U.UserName,
      PreSortedPerUser.Point,
      PreSortedPerUser.Avg_Time,
      @UserRank := if( @lastUserID = PreSortedPerUser.User_ID, @UserRank +1, 1 ) FinalRank,
      @lastUserID := PreSortedPerUser.User_ID
   from
      ( select
              S.user_id,
              S.point,
              S.avg_time
           from
              Scores S
           order by
              S.user_id,
              S.point DESC,
              S.Avg_Time ) PreSortedPerUser
         JOIN Users U
            on PreSortedPerUser.user_ID = U.ID,
      ( select @lastUserID := 0,
               @UserRank := 0 ) sqlvars 
   having
      FinalRank = 1
   order by
      Point Desc,
      Avg_Time

Résultats gérés par SQLFiddle

Notez qu'en raison des variables @ en ligne nécessaires pour obtenir la réponse, il y a deux colonnes supplémentaires à la fin de chaque ligne. Celles-ci ne sont que des "restes" et peuvent être ignorées dans n'importe quelle présentation de sortie que vous essayez de faire ... OU, vous pouvez envelopper le tout au dessus d'un niveau pour obtenir les quelques colonnes que vous voulez, comme

select 
      PQ.UserName,
      PQ.Point,
      PQ.Avg_Time
   from
      ( entire query above pasted here ) as PQ
26
DRapp

je pense que vous manquez de comprendre la relation de table ..

utilisateurs: scores = 1: *

juste join n'est pas une solution.

est-ce votre intention?

SELECT users.username, avg(scores.point), avg(scores.avg_time)
FROM scores, users
WHERE scores.user_id = users.id
GROUP BY users.username
ORDER BY avg(scores.point) DESC, avg(scores.avg_time)
LIMIT 0, 20

(cette requête permet d'obtenir le point moyen et le temps moyen moyen de chaque utilisateur par desc point, asc)

si vous voulez obtenir chaque classement scores? utilisation left outer join

SELECT users.username, scores.point, scores.avg_time
FROM scores left outer join users on scores.user_id = users.id
ORDER BY scores.point DESC, scores.avg_time
LIMIT 0, 20
2
namxee

@DRapp est un génie. Je n'ai jamais compris comment il codait son code SQL. J'ai donc essayé de le coder dans ma propre compréhension.


    SELECT 
      f.username,
      f.point,
      f.avg_time
    FROM
      (
      SELECT
        userscores.username,
        userscores.point,
        userscores.avg_time
      FROM
        (
        SELECT
          users.username,
          scores.point,
          scores.avg_time
        FROM
          scores
        JOIN users
        ON scores.user_id = users.id
        ORDER BY scores.point DESC
        ) userscores
      ORDER BY
        point DESC,
        avg_time
      ) f
    GROUP BY f.username
    ORDER BY point DESC

Le même résultat est obtenu en utilisant GROUP BY au lieu de l'utilisateur @variables.

1
Rad Apdal

grouper par ordre de pk id default donc le résultat
nom d'utilisateur point avg_time
demo123 100 90 ---> id = 4
demo123456 100 100 ---> id = 7
démo 90 120 ---> id = 1

0
babaoqi