web-dev-qa-db-ja.com

MySQL ORDER BY複数列ASCおよびDESC

sersscoresの2つのMYSQLテーブルがあります。詳細:

  • ユーザー表:

enter image description here

  • スコア表:

enter image description here

私の意図は、ポイントフィールドソートDESC(降順)結合avg_timeフィールドソートASC(昇順)を持つ20人のユーザーリストを取得することです。私はクエリを使用します:

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

結果は次のとおりです。

enter image description here

最初の行はポイント= 100およびavg_time = 60であるため、結果は間違っています。

私の望ましい結果は次のとおりです。

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

さまざまなクエリで何度も試しましたが、結果はまだ間違っています。解決策を教えてください。

前もって感謝します!

30
Tan Viet

[OK]を、私はあなたが今何を望んでいると思うと、クエリの前に確認するために明確にしてみましょう。ユーザーごとに1つのレコードが必要です。ユーザーごとに、BEST POINTSスコアレコードが必要です。ユーザーごとの最高のポイントのうち、平均時間が最高のポイントが必要です。すべてのユーザーに「最高」の値を設定したら、最終結果を最初に最高のポイントでソートする必要があります...競争のランキングに似ています。

これでクエリです。上記の記述が正確な場合は、1人あたりの最高ポイント/平均時間を取得し、そのエントリに「ランク」を割り当てることから始める必要があります。これは、MySQL @変数を使用して簡単に実行できます。次に、HAVING句を含めるだけで、それらのレコードが各人について1ランクに維持されます。最後に、最高のポイントと最短の平均時間による順序を適用します。

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

SQLFiddleで処理された結果

回答を取得するために必要なインライン@変数のため、各行の最後に2つの余分な列があります。これらは単に「残り」であり、あなたがしようとしている実際の出力プレゼンテーションでは無視することができます...または、あなたが好きないくつかの列を得るために、1つ以上のレベルの上に全体をラップすることができます

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

テーブルのリレーションについて理解できないと思います。

ユーザー:スコア= 1:*

ただjoinは解決策ではありません。

これはあなたの意図ですか?

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

(このクエリは、各ユーザーの平均ポイントとdescポイント、ascによる平均avg_timeを取得します)avg_time

各スコアのランキングを取得したい場合は?つかいます 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は天才です。彼がSQLをどのようにコーディングしたか理解できなかったので、自分の理解でコーディングしてみました。


    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

ユーザー@variablesの代わりにGROUP BYを使用しても同じ結果が得られます。

1
Rad Apdal

pk idによるデフォルトの順序でグループ化するので、結果
ユーザー名ポイントavg_time
demo123 100 90 ---> id = 4
demo123456 100100 ---> id = 7
デモ90120 ---> id = 1

0
babaoqi