【入門編】【中級】DAO.Recordsetの「FindFirst」と「NoMatch」:クエリを使わずに高速検索を実現する – Access VBA解析バイブル

スポンサーリンク

こんにちは!現場でバリバリとAccessアプリを組んでいると、「画面上の特定のデータを一瞬で探してフォーカスを合わせたい!」という壁にぶつかることがよくありますよね。

マクロの記録から一歩抜け出して、本格的なVBAのコードを書けるようになりたいあなたへ。今回は、Access VBAの真骨頂である「DAO(Data Access Objects)を使った高速レコード検索」について、徹底的に噛み砕いて解説します。

ここをクリアすれば、Access VBAのオブジェクトモデルの動きが手に取るように分かるようになりますよ。さあ、一緒にプロの扉を開きましょう!

1. なぜ「クエリ」や「フィルタ」ではなく「Recordset」なのか?

フォームを開いているとき、特定の条件に合うデータを検索する方法として、よく「フィルター機能」や「再クエリ(Requery)」が使われます。しかし、これらは画面の描画を伴うため、データ量が多くなるとどうしても動作がモタついてしまいます。

そこで登場するのが、メモリ上でデータを直接高速に操作する`DAO.Recordset(レコードセット)`です。

メモリ上のデータ特急便

Recordsetとは、いわばデータベースのテーブルやクエリのデータを「丸ごとメモリ上に切り出したもの」です。
フォームの画面をいじらず、目に見えない裏側の世界(メモリ上)で「この条件に合うデータはどこだ?」と電光石火のスピードで探し出し、合致した瞬間に画面をそのレコードへジャンプさせる。これが、プロが好む最もスマートで高速な手法なのです。

2. 主役の紹介:`FindFirst` と `NoMatch` のコンビネーション

DAOのRecordsetを開いたあと、条件に一致するレコードを頭から探す(Find)ために使うのが `FindFirst` メソッドです。

そして、その相棒となるのが `NoMatch` プロパティ
「お目当てのデータが見つかったかどうか?」を `True` または `False` で教えてくれる、非常に優秀な見張り番です。

2つのメソッドの基本フロー

1. テーブルやクエリからRecordsetを取得する
2. `FindFirst “フィールド名 = 条件”` で検索する
3. `NoMatch` プロパティを確認する

  • `True` なら:データナシ(見つからなかった)
  • `False` なら:データアリ!見つかったレコードへジャンプ完了

3. 【実践】コピペで動く!高速検索コード

それでは、実際の開発現場でそのまま使えるサンプルコードを見てみましょう。
今回は、顧客マクロ(`T_顧客`)から、テキストボックスに入力された「顧客ID」を瞬時に探し出し、フォームの表示をそのデータに合わせる処理を作ります。

シナリオ

  • 検索元のフォーム名:`F_顧客管理`
  • 検索値を入力するテキストボックス:`txt検索ID`
  • 対象テーブル/クエリ:`T_顧客`

Private Sub btn検索_Click()
‘ 変数の宣言(DAOのRecordsetと、現在開いているフォームのレコードセットを扱う変数)
Dim rs As DAO.Recordset
Dim searchID As Long

‘ 1. 検索値が空かチェック
If IsNull(Me.txt検索ID) Then
MsgBox “検索する顧客IDを入力してください。”, vbExclamation, “入力エラー”
Me.txt検索ID.SetFocus
Exit Sub
End If

searchID = Me.txt検索ID.Value

‘ 2. フォームのレコードセットのクローン(複製)を取得する
‘ ※フォームの現在位置を汚さずに、裏で同じデータを操作するために .RecordsetClone を使います
Set rs = Me.RecordsetClone

‘ 3. FindFirstメソッドで条件に一致するレコードを検索
‘ 文字列の場合は ‘ ‘ で囲む必要がありますが、数値型なのでそのまま結合します
rs.FindFirst “顧客ID = ” & searchID

‘ 4. NoMatchプロパティで結果を判定
If rs.NoMatch Then
‘ 見つからなかった場合
MsgBox “指定された顧客ID ” & searchID & ” は見つかりませんでした。”, vbInformation, “検索結果”
Else
‘ 見つかった場合:フォームのブックマークをレコードセットの現在位置に同期させる
Me.Bookmark = rs.Bookmark
MsgBox “該当するデータにジャンプしました!”, vbInformation, “成功”
End If

‘ 5. オブジェクトの解放(メモリリークを防ぐためのプロの作法)
rs.Close
Set rs = Nothing

End Sub

4. ここがプロのこだわり!初心者が陥りやすい罠と対策

上記のコードには、Access VBAを極める上で絶対に知っておくべき「3つの極意」が隠されています。

① `Me.RecordsetClone` を使う理由

フォームを直接操作する `Me.Recordset` をそのまま検索に使うと、検索するたびにフォームの表示位置がガチャガチャと動いてしまい、ユーザービリティが著しく低下します。
「クローン(影武者)」を作ることで、裏でこっそり検索し、見つかった瞬間だけ `Me.Bookmark = rs.Bookmark` で表のフォームをワープさせるというスマートな技が可能になります。

② 文字列型を検索するときの「シングルクォーテーション」の罠

今回のサンプルは「数値型(Long)」のID検索だったので `=” & searchID` で動きましたが、これが「文字列型(Text)」の場合は、次のようにSQLの構文ルールに従って条件式をシングルクォーテーション(`’`)で囲む必要があります。

‘ 氏名などの文字列を検索する場合
Dim searchName As String
searchName = Me.txt検索氏名.Value

‘ 条件式の中にシングルクォーテーションを埋め込む
rs.FindFirst “氏名 = ‘” & searchName & “‘”

このクォーテーションの付け忘れは、中級者でもよくやるエラーナンバー1です。十分に注意してくださいね。

③ 忘れちゃいけない `Set rs = Nothing`

VBAで `DAO.Recordset` を開いたら、処理の最後には必ず `rs.Close` で閉じ、`Set rs = Nothing` でメモリを解放してあげましょう。これをサボると、見えないところでメモリが圧迫され、Accessがフリーズする原因になります。

5. まとめ

いかがでしたか?今回は、DAOの `FindFirst` と `NoMatch` を使った高速検索のテクニックを解説しました。

  • フォームのフィルタ機能よりも、裏のメモリ(RecordsetClone)で探す方が圧倒的に速い。
  • 見つかったかどうかは `rs.NoMatch`(True/False)で判定する。
  • 見つかったら `Me.Bookmark = rs.Bookmark` でフォームの表示を同期させる。

この3つの型をマスターすれば、あなたの作るAccessアプリのスピードと快適性は見違えるほど向上します。ぜひ、実際の開発現場で試してみてくださいね。

ここをクリアしたあなたなら、もうAccess VBAの初級者卒業は目の前です。自信を持って次のステップへ進みましょう!

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