ACCESS 検索フォーム作成方法(VBAコード公開)

ACCESS 検索フォーム作成方法

ACCESSのフォームで最もよく使われるのが検索フォームです。
多くのレコードが有るとその中から特定のレコードを効率よく抽出したいものです。
では、どうやって検索フォームを作成するかを見ていきましょう。


こんにちは。
はこにわガジェット (@hakoniwagadget) です。

ACCESSを使った売上管理、顧客管理などのデータベース開発を行っています。
ACCESSは使いこなすために少しスキルが必要なものの、うまく活用すればExcelよりも業務の効率化が図れます。
この記事ではACCESSで実際に作成したフォームやレポートを、その作成方法と共にご紹介していきます。

ACCESSで作成した検索フォーム(完成形)

まず、作成した検索フォームの機能をご紹介します。
画面は下記の通りです。

これは、売上データを検索するためのフォームで、以下の機能を実装しています。

1.検索条件に応じて、下段のレコード一覧の表示が変わる
2.受注日、売上日、販売チャネルなどの複数の検索条件を組み合わせて検索できる
3.条件クリアボタンを押すと検索条件がクリアされ、レコード一覧も元に戻る
4.売上日順ボタンを押すと売上日順でソートされる
5.作業中のみボタンを押すと売上前の作業中レコードのみ表示される
6.レコード一覧で特定のレコードの売上IDをダブルクリックすると、詳細が表示される

それでは、作り方を順にみていきましょう。

フォームの作成

デザイン

まず、フォーム自体を作成します。
こちらがフォームのデザインビューです。

フォームは帳票フォームを選択します。
帳票フォームは詳細セクション(画面中央)に1レコード分のレイアウトを作成し、それを表のように繰り返すレイアウトです。

検索条件はフォーム上部の「フォームヘッダー」を使って作成します。
詳細セクションはスクロールすると下へ移動していきますが、フォームヘッダーは位置が固定なので検索条件等のずっと表示しておきたいものを配置するのに便利です。

レコードソースの設定

フォームのレコードソースには売上データが入っているテーブルもしくはクエリを指定します。
このデータベースでは売上データが入ったテーブルは「TRN_売上」というテーブルです。
ちなみに、TRNはトランザクションの略です。
私独自の命名規則ですが、処理毎に蓄積されていくデータを入れるテーブルには「TRN_〇〇」と名付けています。
逆に最初から設定しておくデータはマスターデータとして「MST_〇〇」と名付けています。
このあたりの命名規則はご自身が気に入ったものを使っていただけばよいのですが、統一ルールにしておくと間違いが少ないでしょう。

話を戻します。
実は先ほどのフォームではレコードソースを「TRN_売上」にはしていません。

レコードソースは「LIST_売上」という「TRN_売上」を元にした選択クエリにしています。
「TRN_売上」をそのままフォームのレコードソースにしてしまうと不便なことがあるからです。

下記は「TRN_売上」のデータです。
リレーショナルデータベースなので、販売チャネルIDや商品IDは他のテーブルと連携するために、キー値である数値が入っています。
この数値が別の「MST_販売チャネル」や「MST_商品」テーブルと連携することで、商品IDの1は、〇〇〇〇という商品名というように紐づけができていくのです。

フォームのレコードソースに「TRN_売上」自体を使ってしまうと、この値の読み替えができず、フォームの表示が下記のようになってしまいます。

販売チャネルや顧客名、商品名が数値になってしまったのがお分かりいただけると思います。
これでは使いにくいですよね。

コンボボックスによる値の読み替え

これを回避する方法もあるにはあります。
例えば販売チャネルIDのコントロールを右クリックして、コントロールの種類の変更からコンボボックスを選択します。

そして、コンボボックスのプロパティのデータタブで「値集合ソース」に「MST_販売チャネル」を選択します。

更に、書式タブで、列数を2、列幅を0cm、3cmと設定します。

これは、コンボボックスに表示する「MST_販売チャネル」テーブルの値を2列分にするが、1列目は幅を0cmにして表示せず、2列目のみ表示するという設定です。なぜこんなことをするかというと、「MST_販売チャネル」の1列目は販売チャネルIDで数値なので、コンボボックスには必要が無いからです。なお、「MST_販売チャネル」の2列目には販売チャネル名がテキストで入っています。

では、設定を変えた後のフォームを見てみましょう。

販売チャネルの部分がコンボボックスになり、数値ではなく販売チャネル名が表示されていることが分かると思います。
この方法であれば、レコードソースがテーブルであっても必要なデータを見せることができます。

ただ、問題はコンボボックスになってしまうことです。
一般的に検索フォームはデータ入力をさせるフォームではないので、必要な情報が一画面に収まることが重視されます。
コンボボックスにしてプルダウンボタンがつくことで横幅が長くなり一画面に収めにくくなることと、見栄えが悪くなるという問題があります。

完成形の画面を再度提示しましょう。
コンボボックスにしていないので見やすいですよね。

ではどうしたらこの形を実現できるか。

答えは、レコードソースにクエリを使う、です。

レコードソースにクエリを使う

まず、使用するクエリを作成しましょう。
クエリのデザインビューで作成します。
下記のように、元となるテーブル「TRN_売上」からIDで連結したテーブルを接続し、販売チャネル名、顧客名、商品名などのフィールドを各テーブルからクエリに追加していきます。

そして、検索フォームのデザインビューで、レコードソースを変更します。

こうすることにより、レコード一覧が分かりやすい名前で表示できるようになりました。

VBAのプログラミング

検索条件に応じて、下段のレコード一覧の表示が変わる

ここからはこのフォームに実装した、6つの機能の開発方法を説明してきます。
まずは検索フォームの基本である、検索条件に応じてレコード一覧の表示を変える部分です。

このフォームでは各種検索条件を入力した後で、「検索」ボタンを押すと結果が表示されるようにしてあります。
そのため、フォームのデザインビューから検索ボタンのプロパティを見ると、クリック時イベントにイベントプロシージャを設定しています。

では、クリックした際のプロシージャをVBEで見てみましょう。


Option Compare Database
Option Explicit

Dim filter_txt As String

Private Sub 検索_ボタン_Click()

filter_txt = ""

'受注期間
If Me!受注日検索FROM <> "" Then
    
    If Me!受注日検索TO <> "" Then
        
        filter_txt = "受注日 >= #" & Me!受注日検索FROM & "# and 受注日 <= #" & Me!受注日検索TO & "#"
    
    Else
        
        filter_txt = "受注日 >= #" & Me!受注日検索FROM & "#"
        
    End If

ElseIf Me!受注日検索TO <> "" Then

    filter_txt = "受注日 <= #" & Me!受注日検索TO & "#"
        
End If

'販売チャネル
If Me!販売チャネル検索 <> "" Then
       
    If filter_txt = "" Then
       
        filter_txt = "販売チャネルID = " & Me!販売チャネル検索
        
    Else

        filter_txt = filter_txt & " and 販売チャネルID = " & Me!販売チャネル検索
            
    End If
        
End If
    
Me.Filter = filter_txt
Me.FilterOn = True
Me.OrderBy = "受注日 DESC"
Me.OrderByOn = True

若干抜粋してありますが、基本構造は上記の通りです。
「filter_txt」という文字列型の変数を定義して、フォームの抽出条件の設定値に応じて、「filter_txt」にフィルター条件を追記していきます。

例えば最初の受注期間だと、条件分岐を使用して
・「受注日検索FROM」と「受注日検索TO」の両方に値が入っていれば、その間
・「受注日検索FROM」のみに値が入っていれば、「受注日検索FROM」以降の日
・「受注日検索TO」のみに値が入っていれば、「受注日検索TO」以前の日付
という条件式を「filter_txt」に書き込みます。

そのうえで最後に、
Me.Filter = filter_txt
Me.FilterOn = True
と設定して、フォーム自体のフィルター条件に「filter_txt」を設定するのです。
これによって指定した条件に合ったレコードのみが表示されます。

受注日、販売チャネルなどの複数の検索条件を組み合わせて検索できる

2つ目の機能である複数の検索条件を組み合わせて検索する方法です。
こちらは前述のコードの中で、販売チャネルの部分を見てください。


If filter_txt = "" Then

という条件文があります。
これは、「filter_txt」が空、つまりその前にある受注日検索に何も条件が設定されていなかった場合、という意味です。
「filter_txt」が空であれば、単純に「filter_txt」に販売チャネルの条件を入れればよいので、


filter_txt = "販売チャネルID = " & Me!販売チャネル検索

となります。

一方、「filter_txt」が空でない、つまりその前にある受注日検索で条件が設定されていた場合は、二つの条件文を「and」でつなぐ必要があります。そのため、


filter_txt = filter_txt & " and 販売チャネルID = " & Me!販売チャネル検索

となります。

後者では元々の「filter_txt」の文字列(つまり受注日検索の条件文)を活かしつつ、そこに「and」以降の条件を追記していることがお分かりいただけると思います。

このように設定することで検索条件が増えても、最終的に「filter_txt」を使ってフィルターを行えば希望通りのレコード抽出が可能です。

条件クリアボタンを押すと検索条件がクリアされ、レコード一覧も元に戻る

検索を続けていくと、いったん条件をリセットして最初の状態に戻したくなる時があります。
そのために、条件クリアボタンを設けています。
検索条件がクリアされるだけでなく、レコード一覧も初期状態に戻ります。

条件クリアボタンのクリック時イベントに以下のイベントプロシージャを設定しています。


Private Sub 条件クリア_ボタン_Click()

    Me!受注日検索FROM = ""
    Me!受注日検索TO = ""
    Me!売上日検索FROM = ""
    Me!売上日検索TO = ""
    Me!販売チャネル検索 = ""
    Me!顧客名検索 = ""
    Me!商品名検索 = ""
    Me!作業中検索 = True
    Me!完了検索 = True
    Me!キャンセル検索 = False
    filter_txt = ""
    filter_states = ""
    Me.FilterOn = False
    Me.OrderBy = "受注日 DESC"
    Me.OrderByOn = True

End Sub

いくつか並んでいるMe!〇〇 = “”はフォームにある検索条件を設定するコントロールの値をクリアするためのコードです。
これで検索条件を初期状態に戻したうえで、


Me.FilterOn = False

でフィルターを解除してすべてのレコードを表示します。

更に、


    Me.OrderBy = "受注日 DESC"
    Me.OrderByOn = True

で受注日の降順(新しいものが一番上)で並び替えます。

売上日順ボタンを押すと売上日順でソートされる

特定のフィールドの値で並び替えを頻繁に行う場合は、並び替え専用ボタンを設けます。
今回の検索画面は基本的に受注日の降順で並び替えをしていますが、売上日でも並び替えができるようにしました。

そのため、売上日順ボタンのクリック時イベントに以下のイベントプロシージャを設定しています。


Private Sub 売上日順_ボタン_Click()

    Me.OrderBy = "売上日 DESC"
    Me.OrderByOn = True

End Sub

これは割と単純です。
Me.OrderByで指定の並び方に変えるように設定しています。

作業中のみボタンを押すと売上前の作業中レコードのみ表示される

同様に、受注後作業中のレコードのみを簡単に抽出するために専用のボタンを設けました。
作業中のみボタンのクリック時イベントに以下のイベントプロシージャを設定しています。


Private Sub 作業中のみ_ボタン_Click()

    Me.Filter = "ステータスID = 1"
    Me.FilterOn = True
    
End Sub

ステータスID = 1 が、今回のデータベースでは作業中を表すステータスIDになっています。
これも比較的簡単ですね。

レコード一覧で特定のレコードの売上IDをダブルクリックすると、詳細が表示される

最後に非常によく使う機能です。
検索フォームは一画面に収めるために、レコードの中でも全フィールドを表示するのではなく重要なフィールドだけを表示することが多くなります。となると、検索画面でそのままレコードを更新したりすることが難しくなります。

そのため、入力用のフォームは別途作成しておき、検索フォームから全フィールドが表示される入力用フォームを呼び出す、という仕様にするのが便利です。

私はこの機能を作成する際、検索フォームでID(キー値)をダブルクリックすると入力フォームが開く、という仕様を基本としています。
そのため、売上IDにダブルクリック時イベントを設定します。

設定されているイベントプロシージャはこちらです。


Private Sub 売上ID_DblClick(Cancel As Integer)

If IsNull(Me!売上ID) = False Then

    DoCmd.OpenForm "売上入力", , , "売上ID = " & Me!売上ID

Else

    DoCmd.OpenForm "売上入力", , , , acFormAdd

End If

End Sub

IF文で分岐させていますが、条件文が IsNull(Me!売上ID) = False ですので、売上IDがNullでない場合、つまり何からの数値が売上IDに入っている場合が上段になります。


DoCmd.OpenForm "売上入力", , , "売上ID = " & Me!売上ID

というコードで、売上入力フォームを開くのですが、その際WHERE句で売上ID = Me!売上ID と指定してダブルクリックされた売上IDと同じ売上IDのレコードを開きます。

一方でIF条件がFALSE、つまり、売上IDがNULLのレコードをダブルクリックした場合は、


DoCmd.OpenForm "売上入力", , , , acFormAdd

で新規レコードで売上入力フォームを開く、という設定にしてあります。

以上、ACCESSの検索フォーム作成方法をご紹介しました。


ACCESSを使いこなせば、業務の効率化や自動化が実現できます。
しかし、自分でACCESSを学ぶには時間がない、難しそうで不安、という方も多いでしょう。

そんな時は、ACCESS開発歴20年以上、過去に100以上のACCESSデータベースを開発してきた私(@hakoniwagadget)にお任せください。

ACCESSの新規開発、既存のACCESSの修正、ACCESSの操作レッスンなど様々なサービスをご提供しています。
ご興味のある方は下記のサービス一覧をご覧ください。

サービス一覧

最後までお読みいただき、ありがとうございました。