|
| 1 | +# 解説 |
| 2 | + |
| 3 | +## ✅ 解法 1(推奨 / MySQL 8.0+) |
| 4 | + |
| 5 | +```sql |
| 6 | +SELECT |
| 7 | + score, |
| 8 | + DENSE_RANK() OVER (ORDER BY score DESC) AS `rank` |
| 9 | +FROM Scores |
| 10 | +ORDER BY score DESC; |
| 11 | +``` |
| 12 | + |
| 13 | +### ポイント 1 |
| 14 | + |
| 15 | +- `DENSE_RANK()` は「同点は同順位」「次の順位は連番(穴なし)」を自動で満たします。 |
| 16 | +- 問題要件の並び順は `ORDER BY score DESC` だけで OK(ID 順は不要)。 |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## ✅ 解法 2(互換 / MySQL 5.7 など) |
| 21 | + |
| 22 | +ウィンドウ関数が使えない環境では、**相関サブクエリ**で「自分より高い**異なる**スコアの個数 + 1」を順位にします。 |
| 23 | + |
| 24 | +```sql |
| 25 | +SELECT |
| 26 | + s1.score, |
| 27 | + 1 + ( |
| 28 | + SELECT COUNT(DISTINCT s2.score) |
| 29 | + FROM Scores AS s2 |
| 30 | + WHERE s2.score > s1.score |
| 31 | + ) AS `rank` |
| 32 | +FROM Scores AS s1 |
| 33 | +ORDER BY s1.score DESC; |
| 34 | +``` |
| 35 | + |
| 36 | +### ポイント 2 |
| 37 | + |
| 38 | +- `COUNT(DISTINCT s2.score)` により**同点は同じ順位**になる(穴なし= DENSE の性質)。 |
| 39 | +- シンプルで確実ですが、データ量が多いと相関サブクエリで重くなることがあります。 |
| 40 | + |
| 41 | +--- |
| 42 | + |
| 43 | +## (参考)CTE で「重複除去 → 順位 → 突き合わせ」の段階を明示(MySQL 8.0+) |
| 44 | + |
| 45 | +概念的な段階(Distinct → Rank → Join)をクエリ上でも表したい場合: |
| 46 | + |
| 47 | +```sql |
| 48 | +WITH ds AS ( |
| 49 | + SELECT DISTINCT score FROM Scores |
| 50 | +), |
| 51 | +rr AS ( |
| 52 | + SELECT |
| 53 | + score, |
| 54 | + DENSE_RANK() OVER (ORDER BY score DESC) AS `rank` |
| 55 | + FROM ds |
| 56 | +) |
| 57 | +SELECT s.score, rr.`rank` |
| 58 | +FROM Scores AS s |
| 59 | +JOIN rr USING (score) |
| 60 | +ORDER BY s.score DESC; |
| 61 | +``` |
| 62 | + |
| 63 | +--- |
| 64 | + |
| 65 | +## 図解:処理の流れ(ウィンドウ関数版) |
| 66 | + |
| 67 | +> 余計な HTML タグや複雑な改行を排し、Mermaid が壊れにくい最小構成にしています。 |
| 68 | +
|
| 69 | +```mermaid |
| 70 | +flowchart TB |
| 71 | + A[Scores 全行] --> B[降順ソート: score DESC] |
| 72 | + B --> C[DENSE_RANK を各行に適用] |
| 73 | + C --> D[結果を score DESC で出力] |
| 74 | +``` |
| 75 | + |
| 76 | +--- |
| 77 | + |
| 78 | +## 図解:DENSE_RANK の考え方(概念) |
| 79 | + |
| 80 | +```mermaid |
| 81 | +flowchart TB |
| 82 | + A[スコア集合] --> B[等しいスコアをグループ化] |
| 83 | + B --> C[高いスコアから順位を付与] |
| 84 | + C --> D[同点は同じ順位] |
| 85 | + D --> E[次の異なるスコアは直後の整数順位] |
| 86 | +``` |
| 87 | + |
| 88 | +--- |
| 89 | + |
| 90 | +## サンプルに対する出力イメージ |
| 91 | + |
| 92 | +入力: |
| 93 | + |
| 94 | +```text |
| 95 | +id | score |
| 96 | +---+------- |
| 97 | +1 | 3.50 |
| 98 | +2 | 3.65 |
| 99 | +3 | 4.00 |
| 100 | +4 | 3.85 |
| 101 | +5 | 4.00 |
| 102 | +6 | 3.65 |
| 103 | +``` |
| 104 | + |
| 105 | +出力(どの解法でも同じ): |
| 106 | + |
| 107 | +```text |
| 108 | +score | rank |
| 109 | +------+------ |
| 110 | +4.00 | 1 |
| 111 | +4.00 | 1 |
| 112 | +3.85 | 2 |
| 113 | +3.65 | 3 |
| 114 | +3.65 | 3 |
| 115 | +3.50 | 4 |
| 116 | +``` |
| 117 | + |
| 118 | +--- |
| 119 | + |
| 120 | +## つまずきポイントと対策 |
| 121 | + |
| 122 | +- **表示の小数桁**:`score` が `DECIMAL(?,2)` であれば「4.00」のように 2 桁が保たれます。 |
| 123 | + もし `FLOAT/DOUBLE` なら `ROUND(score, 2)` で揃えると安全です(問題文は DECIMAL 前提) |
| 124 | +- **順位の穴**:`RANK()` は「穴あり」になるので、本問題は**必ず `DENSE_RANK()`** を使うか、相関サブクエリで「高い異なるスコア数 + 1」を計算してください。 |
| 125 | +- **パフォーマンス**:巨大テーブルではウィンドウ関数が高速なことが多いです。5.7 の相関サブクエリ版はインデックス(`score`)である程度は緩和できます。 |
| 126 | + |
| 127 | +--- |
0 commit comments