【実務・中級編】DAO.RecordsetのFilterプロパティとRecordsetCloneを組み合わせた高速検索エンジン – Access VBA解析バイブル

スポンサーリンク

Access VBAの「脱・クエリ再生成」:RecordsetCloneとFilterを極め、UIを爆速化する

Access開発の現場で、検索機能を作るたびに「SQL文を文字列結合してクエリを書き換える」という原始的な手法をとっていないだろうか?

その設計は、ネットワークトラフィックの無駄な増大を招き、データベースエンジンを疲弊させ、何より「ユーザー体験」を著しく損なう。プロフェッショナルは、メモリ上のレコードセットを操る。

今回は、DAO.Recordsetの`Filter`プロパティと`RecordsetClone`を組み合わせ、Accessフォームを「高速検索エンジン」へと変貌させるための極限の技法を伝授する。

なぜ「SQLの都度生成」は悪手なのか

フォームの検索機能で `Me.RecordSource = “SELECT FROM … WHERE …”` を繰り返すと、毎回Jet/ACEエンジンがクエリを解析・最適化するオーバーヘッドが発生する。大規模なデータになればなるほど、この遅延は顕著になる。

我々が目指すべきは、「一度開いたデータセットをメモリ上に保持し、その上で絞り込みを行う」というアプローチだ。

核心技術:RecordsetClone と Filter の連携

`RecordsetClone`は、現在のフォームが参照しているデータソースの「分身」をDAO.Recordsetとして取得するプロパティだ。この分身に対して`Filter`を適用し、フォームの`Bookmark`を同期させる。これだけで、クエリ再実行なしに表示を瞬時に更新できる。

実装のプロダクションコード

保守性を担保するため、以下のコードは検索条件を引数で受け取る単一のサブプロシージャとして設計している。フォームの検索ボタンから呼び出すことを想定してほしい。

‘ 検索を実行する汎用プロシージャ
‘ @param strFilter 検索条件文字列 (WHERE句の条件部分)
Public Sub ApplySearchFilter(ByVal strFilter As String)
Dim rs As DAO.Recordset

‘ エラーハンドリングは堅牢な開発の基本
On Error GoTo ErrorHandler

‘ 1. 現在のフォームのレコードセットを複製
Set rs = Me.RecordsetClone

‘ 2. フィルタの適用
‘ Filterを空にすると全件表示になるよう設計
rs.Filter = strFilter

‘ 3. フィルタ後のレコードセットをセット
‘ RecordsetCloneに対してFilterを適用した結果を開き直す
Set rs = rs.OpenRecordset()

‘ 4. フィルタ結果が0件の場合のハンドリング
If rs.EOF Then
MsgBox “該当するデータは見つかりませんでした。”, vbInformation
rs.Close
Exit Sub
End If

‘ 5. フォームのブックマークを同期
‘ これにより、画面表示が検索結果へ瞬時に切り替わる
Set Me.Recordset = rs

‘ メモリ解放の作法
rs.Close
Set rs = Nothing
Exit Sub

ErrorHandler:
MsgBox “エラー番号: ” & Err.Number & vbCrLf & “内容: ” & Err.Description, vbCritical
If Not rs Is Nothing Then Set rs = Nothing
End Sub

現場で生き残るための設計原則

この手法を採用する上で、必ず守るべき「3つの鉄則」がある。

1. フィルタ文字列のクレンジング

ユーザーが入力した値をそのまま `Filter` に渡してはならない。シングルクォーテーションのエスケープ処理(`Replace(str, “‘”, “””)`)を怠ると、悪意のある入力や記号によるSQLインジェクション的挙動、あるいは単純な構文エラーでシステムが停止する。

2. インデックスの有効活用

`Filter`プロパティはDAOの機能だが、対象となるテーブルのフィールドにインデックスが貼られていなければ、検索速度は劇的に低下する。特に検索対象となるフィールドには、あらかじめインデックスを設計しておくのがデータベースアーキテクトの最低限の義務だ。

3. Recordsetの破棄を忘れない

`RecordsetClone`や`OpenRecordset`で生成したオブジェクトは、VBAのガベージコレクションに頼ってはいけない。`Set rs = Nothing` を呼び出すまでメモリを占有し続ける。「開いたら閉じる」のスコープを関数内に閉じ込めることで、メモリリークを根絶せよ。

まとめ:次の一歩

この手法を導入すれば、フォームの検索処理は「クエリの再評価」という重い作業から解放され、メモリ上の操作による「ミリ秒単位の応答」へと進化する。

次にあなたが取り組むべきは、検索条件が複雑化した場合の「動的フィルタ生成クラス」の作成だ。`Filter`文字列を泥臭い文字列結合で作るのではなく、Dictionaryオブジェクトを用いてスマートに構築する設計へ移行すれば、あなたのツールはプロのプロダクションコードとして確固たる地位を築くだろう。

コードは嘘をつかない。論理的な設計こそが、Accessの限界を超える唯一の道だ。

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