メディア掲載: レバテックフリーランス様のサイトで当ブログが紹介されました

【Access】最大値・最小値をもつレコードを抽出する方法

  • 成績テーブルから、各生徒の最高点のレコードだけ抽出したい
  • 購入履歴テーブルから、各顧客の最新の購入レコードだけ抽出したい

このような場合、DMax関数・DMin関数を使ったり、中間クエリを使うことで目的のデータを抽出することができます。

今回のサンプル

サンプルとして、生徒が3人、それぞれに3科目分(数学・国語・英語)のテスト結果のレコードが存在する、合計9行のデータを用意しました。(IDは生徒を識別する番号)

生徒3人分、それぞれ3科目で合計9行からなるテスト結果テーブル
こんな感じのデータを・・・
各生徒ごとに、最高得点のレコードのみが抽出されている
こうしたい

元のテーブル(テスト結果テーブル)から、それぞれの生徒の最高得点のレコードだけを抽出してみます。(ID=s002の生徒は、数学・英語が同点なので2行抽出されます。)

中間クエリを使う方法

まずは、より簡単な中間クエリを使う方法(クエリを重ねる方法)を説明します。

最初に、各生徒ごとの最高得点を算出するクエリを作成します。

グループ化と集計(最大)を使って、生徒ごとの最高点を取得する中間クエリ
IDでグループ化して、得点の「最大」を抽出する(最低得点を抽出したい場合は、得点の集計に「最小」を選んでください)

次に、テスト結果テーブルと、先ほど作成したクエリ(生徒ごとの最大得点)を結合すればOKです。
下図のように、IDID得点得点の最大をつなげます。

テスト結果テーブルと中間クエリを結合することで、最高点のデータのみに絞り込む

このクエリを実行すると、期待したとおりのレコードが抽出されました。

期待通り、生徒ごとの最高得点のレコードのみが抽出された。
生徒ごとの最高得点のレコードが抽出された

DMax関数を使う方法

続いて、DMax関数関数を使う方法です。

長くなるので、先に結論を言うと、今回のケースで生徒ごとの最高得点のレコードだけ抽出するには、得点フィールドの抽出条件を下記のようにすればOKです。

DMax("得点","テスト結果","ID = '" & [ID] & "'")

DMax関数について & 練習

DMax関数は、指定した列から最大値を抽出する関数で、オプションとして検索条件を指定することもできます。(なお、DMin関数は最小値を抽出します)

DMax("列名","テーブル・クエリ名","条件式")

まずは練習として、簡単な条件で動かしてみます。
生徒は識別せずに、全てのレコードにおける得点の最大値を取得してみます。

生徒3人分、それぞれ3科目で合計9行からなるテスト結果テーブル
元となるテスト結果テーブル
DMax関数の結果をイメージするため、新たなフィールド(最高得点)を作成する
全てのレコードの中の最高得点を表示するフィールドを作ってみる。
最高得点: DMax("得点","テスト結果")
最高得点フィールドには、テーブル全体の最高点である90点が表示された
全体の最高得点である 90 が取得された

生徒ごとの最高得点を取得する

テーブル全体の最高得点である90点は取得できましたが、本当に欲しい値は生徒ごとの最大値でしたね。式を変更(条件を追加)して、IDごとの最高得点を取得してみます。

先ほどの式にIDを指定する条件を追加する。
まずは新たなフィールドを作ってDmax関数の結果を確認する
最高点: DMax("得点","テスト結果","ID = '" & [ID] & "'")

クエリを実行すると、期待どおり生徒ごとの最高得点が取得できました。

生徒ごとの最高点がDMax関数によって取得できている
生徒ごとの最高得点(s001: 90, s002: 80, s003: 60)を取得できた

"ID = '" & [ID] & "'" の部分はかなりわかりにくいので、例を代入して説明します。

// 仮にs001が検索条件だった場合(s001は文字列なのでシングルクオートで囲む)
DMax("得点","テスト結果","ID = 's001'")

// 本当の検索条件はIDフィールドなので、s001 => [ID]に書き換える
DMax("得点","テスト結果","ID = '[ID]'")

// 上記のままだと、'[ID]'という文字列として検索してしまうので、
// ① ID = '   ② [ID]   ③ '   という3つにわけて、& でつなぐ(②以外は文字列なので"で囲む)
DMax("得点","テスト結果","ID = '" & [ID] & "'")

最高得点を抽出条件に利用する

生徒ごとの最高得点を取得する式ができ、結果の確認もできたので、得点フィールドの抽出条件に式を移して実行します。

検証した数式を、「得点」フィールドの抽出条件に移す
フィールドを使った検証ができたので、抽出条件に移動させた。当然、先頭にあった「最高点: 」は取り除く。
期待どおり、生徒ごとに最高得点をもつレコードが抽出された
期待したとおりの抽出結果となった。

このように、DMax関数を使うことで、最大値をもつレコードを抽出することができました。

補足:DMin関数で最小値をもつレコードを取得する

最小値をもつレコード(≒最も点数が低かった成績データ)をDMin関数で取得できます。
使い方はDMax関数と全く同じです。

DMaxをDMinに書き換えた
DMax関数と使い方は全く同じ
DMin("得点","テスト結果","ID = '" & [ID] & "'")
期待どおり、生徒ごとの最低得点のレコードが抽出された
こちらも期待したとおりの結果となった。

補足:条件をさらに増やしてみる

ここまでは、生徒ごとの最高得点のレコードという条件でしたが、もう少し複雑にして、指定した試験日の生徒ごとの最高得点のレコードを取得してみます。

テスト結果テーブルには、あらたな列(試験日)を追加しました。

数学は11/19、国語・英語は11/20に実施されたことにする

まずは、生徒ごとの指定日の最高点を新規フィールドに表示してみます。
なお、指定日はクエリの利用者がyyyy/mm/dd形式で入力できるようにしておきます。

生徒ごとの指定日の最高点を表示するフィールドを作成。
指定日の最高点: DMax("得点","テスト結果","ID = '" & [ID] & "' and 試験日 = #" & [指定日は?(yyyy/mm/dd)] & "#")

実行した結果は下図のとおりです。
指定日を2022/11/19にしたパターン(画像上)と、指定日を2022/11/20にしたパターン(画像下)を試してみました。

いずれも期待通りの点数が取得できている

いずれも、期待したとおり、生徒ごとの指定日の最高点が取得できましたので、この式を得点フィールドの抽出条件として使ってみます。

式を得点フィールドの抽出条件に移動

指定日を2022/11/20として実行してみましが、うまくいっていません。
s002の生徒については、試験日が指定日ではないデータ(2022/11/19)も抽出されています。

関係ないデータが抽出されてしまった・・・

得点でしか絞り込みをしていなかったため、別日の同一得点のデータが抽出されてしまっていますね。
試験日フィールドにも抽出条件を設定しておきます。

「試験日」もただしく絞り込まれるように修正

実行してみると、今度は期待どおり生徒ごとの指定日の最高点のレコードが抽出されました。

正直、このケースについて、私は理解に苦労してしまいました。

条件式がある程度複雑になるようであれば、最初に紹介した中間クエリを使う方法の方が、わかりやすいんじゃないかな〜と思います。

補足:別のテーブルからもデータ取得できる

先ほどの例は、テスト結果テーブルだけで全て完結する例でした。
DMax関数・DMin関数は、他のテーブルからデータを取得することもできるので、サンプルを紹介します。

新たに生徒一覧テーブルを用意しました。

生徒一覧テーブルのフィールドに加え、テスト結果テーブルから取得したその生徒の最高得点を取得してみます。

最高得点: DMax("得点","テスト結果","ID = '" & [ID] & "'")

実行した結果は下図のとおりです。

期待どおり、その生徒の最高得点を取得できた。

あまりいいユースケースが思い付かず、こんな感じの例になってしまいました。
個人的には、このパターンではDMax関数を使わず、両テーブルを結合し、グループ化して最大値を取得するほうが好きです。

コメント

タイトルとURLをコピーしました