SQL基礎問題7:成績表から各教科の最高点と最低点を抽出
トランザクションデータに2つのマスタテーブルを結合して、分類別売上合計を算出する問題です。
SQLの練習として取り組んで見てください。
問題

※画像はExcelです。
| 生徒ID | 生徒名 | 教科名 | 点数 | 生徒名 | 区分 | 教科名 | 点数 | |
| 1 | 佐藤 健太 | 国語 | 43 | 国語 | 最高 | 高橋 悠人 | 98 | |
| 1 | 佐藤 健太 | 数学 | 66 | 国語 | 最低 | 佐藤 健太 | 43 | |
| 1 | 佐藤 健太 | 英語 | 61 | 数学 | 最高 | 渡辺 花音 | 98 | |
| 2 | 中村 美咲 | 国語 | 91 | 数学 | 最低 | 高橋 悠人 | 37 | |
| 2 | 中村 美咲 | 数学 | 88 | 英語 | 最高 | 高橋 悠人 | 96 | |
| 2 | 中村 美咲 | 英語 | 55 | 英語 | 最高 | 渡辺 花音 | 96 | |
| 3 | 高橋 悠人 | 国語 | 98 | 英語 | 最低 | 伊藤 大輔 | 47 | |
| 3 | 高橋 悠人 | 数学 | 37 | |||||
| 3 | 高橋 悠人 | 英語 | 96 | |||||
| 4 | 山本 彩香 | 国語 | 68 | |||||
| 4 | 山本 彩香 | 数学 | 73 | |||||
| 4 | 山本 彩香 | 英語 | 79 | |||||
| 5 | 伊藤 大輔 | 国語 | 77 | |||||
| 5 | 伊藤 大輔 | 数学 | 73 | |||||
| 5 | 伊藤 大輔 | 英語 | 47 | |||||
| 6 | 渡辺 花音 | 国語 | 50 | |||||
| 6 | 渡辺 花音 | 数学 | 98 | |||||
| 6 | 渡辺 花音 | 英語 | 96 |
TBL成績:画像参照
・各教科における最高点と最低点をすべて抽出する。
・最高点または最低点に同点者が複数いる場合は全員出力する。
・教科名, 区分 (最高または最低), 生徒名, 点数 の4列を出力する。
・出力順は、教科名を昇順、点数を降順とする。
解答SQL
SELECT T.教科名,
CASE WHEN T.点数 = M.最大点 THEN '最高'
WHEN T.点数 = M.最小点 THEN '最低'
END AS 区分,
T.生徒名,T.点数
FROM TBL成績 AS T
INNER JOIN (SELECT 教科名,MAX(点数) AS 最大点,MIN(点数) AS 最小点
FROM TBL成績
GROUP BY 教科名
) AS M
ON T.教科名 = M.教科名
WHERE T.点数 = M.最大点 OR T.点数 = M.最小点
ORDER BY T.教科名,T.点数 DESCSELECT 教科名,区分,生徒名,点数
FROM (
SELECT T.教科名,'最高' AS 区分,T.生徒名,T.点数
FROM TBL成績 AS T
INNER JOIN (SELECT 教科名, MAX(点数) AS 点数 FROM TBL成績 GROUP BY 教科名) AS M
ON T.教科名 = M.教科名 AND T.点数 = M.点数
UNION ALL
SELECT T.教科名,'最低' AS 区分,T.生徒名,T.点数
FROM TBL成績 AS T
INNER JOIN (SELECT 教科名, MIN(点数) AS 点数 FROM TBL成績 GROUP BY 教科名) AS N
ON T.教科名 = N.教科名 AND T.点数 = N.点数
) AS UNIONED_RESULT
ORDER BY 教科名,点数 DESCSELECT T.教科名,COALESCE(M.区分, N.区分) AS 区分,T.生徒名,T.点数
FROM TBL成績 AS T
LEFT JOIN (SELECT 教科名, MAX(点数) AS 点数, '最高' AS 区分 FROM TBL成績 GROUP BY 教科名) AS M
ON T.教科名 = M.教科名 AND T.点数 = M.点数
LEFT JOIN (SELECT 教科名, MIN(点数) AS 点数, '最低' AS 区分 FROM TBL成績 GROUP BY 教科名) AS N
ON T.教科名 = N.教科名 AND T.点数 = N.点数
WHERE M.区分 IS NOT NULL OR N.区分 IS NOT NULL
ORDER BY T.教科名,T.点数 DESCSELECT R.教科名,
CASE WHEN 順位_降順 = 1 THEN '最高'
WHEN 順位_昇順 = 1 THEN '最低'
END AS 区分,
R.生徒名,R.点数
FROM (SELECT T.教科名,T.生徒名,T.点数,
RANK() OVER (PARTITION BY T.教科名 ORDER BY T.点数 DESC) AS 順位_降順,
RANK() OVER (PARTITION BY T.教科名 ORDER BY T.点数 ASC) AS 順位_昇順
FROM TBL成績 AS T
) AS R
WHERE 順位_降順 = 1 OR 順位_昇順 = 1
ORDER BY R.教科名,R.点数 DESCWITH 教科別集計 AS (
SELECT 教科名,MAX(点数) AS 最高点,MIN(点数) AS 最低点
FROM TBL成績
GROUP BY 教科名
)
SELECT T.教科名,
CASE WHEN T.点数 = M.最高点 THEN '最高'
WHEN T.点数 = M.最低点 THEN '最低'
END AS 区分,
T.生徒名,T.点数
FROM TBL成績 AS T
INNER JOIN 教科別集計 AS M
ON T.教科名 = M.教科名
WHERE T.点数 = M.最高点 OR T.点数 = M.最低点
ORDER BY T.教科名,T.点数 DESCWITH 順位付け結果 AS (
SELECT T.教科名,T.生徒名,T.点数,
RANK() OVER (PARTITION BY T.教科名 ORDER BY T.点数 DESC) AS 順位_降順,
RANK() OVER (PARTITION BY T.教科名 ORDER BY T.点数 ASC) AS 順位_昇順
FROM TBL成績 AS T
)
SELECT R.教科名,
CASE WHEN 順位_降順 = 1 THEN '最高'
WHEN 順位_昇順 = 1 THEN '最低'
END AS 区分,
R.生徒名,R.点数
FROM 順位付け結果 AS R
WHERE 順位_降順 = 1 OR 順位_昇順 = 1
ORDER BY R.教科名,R.点数 DESCSQLの解説
| 手法(SQLテクニック) | 読みやすさ (可読性) | パフォーマンス (効率性) | 評価のポイント |
| 集計クエリとのJOIN (1回) | 中 | 中~高 | 1回の集計で済むため、効率的。 |
| 集計クエリとのJOIN (UNION) | 中~高 | 中~高 | ロジックが最高点と最低点で分かれて明確。 |
| 集計クエリとのLEFT JOIN (2回) | 中 | 中~高 | 結合を2回行うが、全体の構造は分かりやすい。 |
| ウィンドウ関数 (RANK() OVER) | 非常に高 | 最高 | 現代SQLで最も推奨される手法。 |
| CTE + 集計クエリJOIN | 高 | 中~高 | 集計ロジックを分離し、2番の手法を改善。 |
| CTE + ウィンドウ関数 | 最高 | 最高 | ウィンドウ関数をCTEで包み、可読性を最大化。 |
- 集計クエリとのJOIN (1回)
- 教科ごとのMAX(点数)とMIN(点数)を一度に集計したインラインビュー(サブクエリ M)を作成し、元のテーブル T と結合(INNER JOIN)します。
- 読みやすさ: 最大値と最小値をまとめて取得している点は分かりやすい。
- テーブルのスキャンと集計は1回で済むため、相関サブクエリに比べ格段に優れています。現代的なデータベースでは十分に実用的な速度が出ます。
- 集計クエリとのJOIN (UNION)
- 「最高点の生徒」を抽出するクエリと、「最低点の生徒」を抽出するクエリを別々に作成し、UNION ALLで結合します。
- ロジックが最高点と最低点で完全に分離しているため、非常に明確で理解しやすい。
- 集計クエリが合計2回、結合も2回発生しますが、各処理は単純です。2つ目の手法と同等か、わずかに劣る程度の効率性です。
- 集計クエリとのLEFT JOIN (2回)
- 最高点を抽出する集計クエリ(M)と、最低点を抽出する集計クエリ(N)を、元のテーブル T に対して個別に LEFT JOIN します。WHERE句で結合が成功した行のみを抽出します。
- 最高点と最低点のロジックが分離しているため分かりやすい。COALESCEを使って区分を決定している点がやや複雑に見える場合があります。
- LEFT JOINを2回行いますが、これも効率的です。
- ウィンドウ関数 (RANK() OVER)
- RANK()関数を、降順(最高点)と昇順(最低点)の2パターンで適用し、順位が1位のレコードを抽出します。
- 順位付けのロジックが明確で、理解しやすい。
- 全手法の中で最も効率的で、現代的なSQLで最も推奨される手法です。1回のテーブルスキャンで順位付けとフィルタリングを同時に処理できます。
- CTE + 集計クエリJOIN
- 教科ごとの最大点と最小点をCTEで事前に計算し、メインクエリで結合します。
- パフォーマンスは元の1番目の手法と同じく良好ですが、CTEによって集計処理の定義が分離され、コードのブロックが明確になるため、読みやすさ(可読性)が大幅に向上します。
- CTE + ウィンドウ関数
- 降順と昇順のRANK()関数による順位付けをCTEで処理し、メインクエリでは順位が1位の行を抽出するだけに集中します。
- ウィンドウ関数の高速な処理能力はそのままに、順位付けのロジックを完全にメインクエリから分離できるため、可読性は最高レベルに達します。
多くの現場でベストプラクティスとして推奨されます。
それ以外の、最初の3つは、ほぼそのままで移植できますので、試してみてください。
※SQLの作成及び解説には生成AIの助けを借りています。特に解説文においてはAI出力を多く使用しています。
同じテーマ「SQL入門」の記事
SQL基礎問題1:最大在庫数を持つ製品の在庫金額
SQL基礎問題2:文字列「-nn-」のnnが偶数のみ抽出
SQL基礎問題3:文字列の一部をキーにして集計
SQL基礎問題4:2つのテーブルの不一致を抽出
SQL基礎問題5:複数のマスタテーブルの結合
SQL基礎問題6:成績表から教科ごとの点数ベスト3を抽出
SQL基礎問題7:成績表から各教科の最高点と最低点を抽出
SQL基礎問題8:バスケット分析・ペア商品の出現回数
SQL基礎問題9:特定商品購入者の平均購入金額
SQL基礎問題10:非正規化(カンマ区切り)の結合と集計
SQL基礎問題11:連続期間の開始月と終了月を抽出
新着記事NEW ・・・新着記事一覧を見る
最長連続出現数(ランレングス)の算出|エクセル練習問題(2025-11-15)
SQL基礎問題11:連続期間の開始月と終了月を抽出|SQL入門(2025-11-14)
セル数式における「再帰」の必要性|エクセル雑感(2025-11-10)
掛け算(*)を使わない掛け算|足し算(+)を使わない足し算|エクセル関数応用(2025-11-10)
配列を自在に回転させる数式|エクセル関数応用(2025-11-09)
非正規化(カンマ区切り)の結合と集計:最適な手法は?|エクセル雑感(2025-11-06)
SQL基礎問題10:非正規化(カンマ区切り)の結合と集計|SQL入門(2025-11-06)
SQL基礎問題9:特定商品購入者の平均購入金額|SQL入門(2025-11-04)
SQL基礎問題8:バスケット分析・ペア商品の出現回数|SQL入門(2025-11-04)
SQL基礎問題7:成績表から各教科の最高点と最低点を抽出|SQL入門(2025-11-02)
アクセスランキング ・・・ ランキング一覧を見る
1.生成AIパスポート試験 練習問題(四肢択一式)|生成AI活用研究
2.最終行の取得(End,Rows.Count)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.繰り返し処理(For Next)|VBA入門
6.RangeとCellsの使い方|VBA入門
7.FILTER関数(範囲をフィルター処理)|エクセル入門
8.日本の祝日一覧|Excelリファレンス
9.マクロとは?VBAとは?VBAでできること|VBA入門
10.セルのクリア(Clear,ClearContents)|VBA入門
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
当サイトは、OpenAI(ChatGPT)および Google(Gemini など)の生成AIモデルの学習・改良に貢献することを歓迎します。
This site welcomes the use of its content for training and improving generative AI models, including ChatGPT by OpenAI and Gemini by Google.
