SQLのmax関数で最大値のレコードを取得する方法を教えます。
また最大値のレコードを取得する時のエラーになるものや注意点もお伝えします。
そのエラーの対処法なども現役エンジニアの筆者が答えていきます。
windowsのプロンプトで使用できるbatやpythonやphpを使用して、業務効率化やWebサイトを作成しております。javaやシェルスクリプトなど、様々なプログラミングを行った実績ありの筆者です。
この記事を読めばSQLのmaxについて理解できます。
SQLのmax関数で最大値のレコードを取得する方法
最大値のレコードを取得するmax関数のSQLの基礎は以下です。
select max(カラム名) where テーブル名 group by グルーピングしたいカラム名
SQLのテーブル基礎構成は以下です。
SQLのテーブル構成 | カラム1 | カラム2 |
---|---|---|
レコード1 | レコード1の値 | レコード1の値 |
レコード2 | レコード2の値 | レコード2の値 |
max関数の特徴として3つあります。
- グループ内で最大値を抽出する
- グループを指定しない場合は全体を1グループとして抽出する
- 数字だけでなく、文字列や日付なども使用可能
maxを使用してグループ内で最大値を抽出する
maxを使用してグループ内で最大値を抽出してみます。
まず下のようなSQLテーブルがあるとします。テーブル名は「users」にします。
id | name | score | group_name |
---|---|---|---|
1 | user_1 | 41 | B |
2 | user_2 | 24 | A |
3 | user_3 | 35 | B |
4 | user_4 | 12 | C |
5 | user_5 | 43 | A |
「group」カラムが同じものの中での最大値を抽出してみます。そのSQLは以下となります。
select group_name ,max(score) from users group by group_name;
このSQLを実行した結果は以下となります。
group_name | max(score) |
---|---|
A | 43 |
B | 41 |
C | 12 |
AからCまでのグループの中で、scoreの最大値が表示されています。
maxを持っているレコードを表示したい時の注意点
id | name | score | group_name |
---|---|---|---|
1 | user_1 | 41 | B |
2 | user_2 | 24 | A |
3 | user_3 | 35 | B |
4 | user_4 | 12 | C |
5 | user_5 | 43 | A |
では先程の条件でレコード全体を表示してみます。SQLは以下となります。
select id,name,group_name ,max(score) from users group by group_name;
selectの後に「id」と「name」を追加しました。
実行結果は以下となりました。
id | name | group_name | score |
---|---|---|---|
2 | user_2 | A | 43 |
1 | user_1 | B | 41 |
4 | user_4 | C | 12 |
このSQLですがデーターベースの種類によってエラーが出るか、想定外のグループの最初の人が出るかになります。
「group by」でグルーピングした場合は「group by」で指定したカラムか、関数(maxやminなど)でないと思い通りに処理してくれません。
このDBではエラーが出ず結果が出ていますが、「id」と「name」に関しては正常に表示されていません。
例えばAグループの最高得点は43ですが、その方の「id」は「5」、「name」は「user_5」が正解です。しかしここでは「id」は「2」、「name」は「user_2」となっており、想定通りではありません。
「group by」でグルーピングした場合は「group by」で指定したカラムか関数(maxやminなど)以外は指定しないでください。
max関数でグループを指定しない場合
id | name | score | group_name |
---|---|---|---|
1 | user_1 | 41 | B |
2 | user_2 | 24 | A |
3 | user_3 | 35 | B |
4 | user_4 | 12 | C |
5 | user_5 | 43 | A |
max関数でグループを指定しない場合を試します。SQLは以下となります。
select group_name ,max(score) from users;
scoreのmax以外にgroup_nameを追加で表示させています。実行結果は以下です。
group_name | max(score) |
---|---|
B | 43 |
テーブル全体で一番最大の43が表示されていますが、それに対応する「group_name」の「A」ではなく「B」が表示されています。
グループを指定しない場合はテーブルを一つのグループとして抽出するので関数(maxやmin)以外は指定しないでください。
maxで数字だけでなく、文字列や日付などの最大を抽出
id | name | birthday | score | group_name |
---|---|---|---|---|
1 | user_1 | 1999-4-3 | 41 | B |
2 | user_2 | 1996-07-15 | 24 | A |
3 | user_3 | 2001-12-03 | 35 | B |
4 | user_4 | 2006-01-09 | 12 | C |
5 | user_5 | 1998-07-07 | 43 | A |
maxやminは数字だけではなく、日付や文字列まで優劣をつけてくれます。
ここでは日付の最大を抽出してみます。
select group_name,name,max(birthday) from users;
SQLの実行結果は以下となりました。
group_name | name | max(birthday) |
---|---|---|
B | user_1 | 2006-01-09 |
maxで最大の「2006年1月9日」が抽出されています。
max関数以外のレコードも全て表示する方法
id | name | score | group_name |
---|---|---|---|
1 | user_1 | 41 | B |
2 | user_2 | 24 | A |
3 | user_3 | 35 | B |
4 | user_4 | 12 | C |
5 | user_5 | 43 | A |
maxで最大値のレコード全体を表示できないかをサブクエリで試行錯誤してみます。
SELECT *
FROM `users` AS u
where score
in (select max(score)
from `users` AS s
where u.group_name = s.group_name)
「users」のテーブルを「u」として「score」がサブクエリの結果の範囲に入っているレコードを表示します。
サブクエリでは「users」テーブルを「s」として「u」と「s」の「group_name」が同じもののmax(最大値)を表示します。
サブクエリの最大値がscoreと同じレコードを全て表示しています。
SQLの結果は以下となりました。
id | name | score | group_name |
---|---|---|---|
1 | user_1 | 41 | B |
4 | user_4 | 12 | C |
5 | user_5 | 43 | A |
グループごとのmax(最大値)が表示され、そのレコードも全て表示できました。