【入門編】QueryDefを活用した「非連結フォーム」の動的フィルタリング:レコードソースを汚さない検索画面の作り方 – Access VBA解析バイブル

スポンサーリンク

こんにちは!Accessでのシステム開発、日々の試行錯誤お疲れ様です。

マクロの記録から一歩抜け出し、「そろ本格的なVBAを書いて業務を効率化したい!」と思っているあなたへ。今日は、Access開発において避けて通れない、しかしここを抑えれば一段上のエンジニアになれる「QueryDef(クエリデフィニション)を使った動的フィルタリング」についてお話しします。

「検索フォームを作るたびに、フォームのレコードソースを直接SQLで書き換えている……」
もしあなたがそんなコードを書いているなら、ちょっと待ってください!その方法、マルチユーザー環境でエラーの温床になりますし、何よりAccessのパフォーマンスを殺してしまう原因になります。

今回は、レコードソースを汚さずに、安全かつ高速に検索画面を作るための極意を、優しく丁寧にお伝えしますね。ここをクリアすれば、Access VBAの基本と「正しい設計思想」はバッチリです!

—

1. なぜ「レコードソース直書き」は危険なのか?

検索フォームを作る時、よく見かけるのがこんなコードです。

‘ 【やってはいけないアンチパターン】
Me.RecordSource = “SELECT FROM T_受注 WHERE 顧客名 LIKE ‘” & Me.txtKeyword.Value & “‘”

一見、動いて便利そうに見えますよね。しかし、これには致命的なデメリットが3つあります。

1. マルチユーザー環境での衝突(ロックと競合)
複数人が同時にこのフォームを開いたとき、フォームのプロパティ(レコードソース)を直接いじると、Access内部で余計な一時テーブルやコンパイルが発生し、動作が不安定になります。
2. コンパイルエラーの温床(SQLインジェクション的リスク)
テキストボックスに入力された文字にシングルクォーテーション(`’`)などが含まれていると、SQL文が構文エラーを起こしてシステムが止まります。
3. 実行計画の破棄(パフォーマンスの低下)
Access(Jet/ACEエンジン)は、クエリの実行計画を最適化しようとしますが、文字列として毎回バラバラのSQLを投げられると、キャッシュが効かず、データ量が増えたときに急激に遅くなります。

ここで登場するのが、今回マスターする「QueryDef」です。

—

2. QueryDef(クエリデフィニション)とは何か?

一言で言うと、QueryDefとは「Accessの裏側にあらかじめ実体として登録されている、クエリの設計図(オブジェクト)」のことです。

ナビウーペン(画面左側)の「クエリ」タブに並んでいるアレらを、VBAから自由自在に召喚・操作するのがQueryDefの正体です。

非連結フォーム(テキストボックスやボタンだけを置き、レコードソースを直接バインドしないフォーム)から、検索条件だけをQueryDefに渡し、そのQueryDefの結果をフォームのソースとして安全に紐解く。これが、プロが使う「レコードソースを汚さない検索画面」の設計手法です。

—

3. 実践!動的フィルタリング検索フォームの作り方

それでは、実際に動くコードを見ていきましょう。
今回は、`T_案件` というテーブルから、「案件名」と「担当者」で絞り込みを行う検索画面を想定します。

ステップ1:ベースとなる「パラメータ付きクエリ」を準備する

まず、Accessのクエリデザイン画面で、あらかじめベースとなるクエリを作っておきます。名前は `qry_案件検索_Base` としましょう。

SQLビューで見ると、こんなイメージです。

SELECT FROM T_案件
WHERE 案件名 LIKE “” & [prm案件名] & “”
AND 担当者 LIKE “” & [prm担当者] & “”;

※ポイントは、テーブルを直接イジるのではなく、`[prm案件名]` という「パラメータ(変数のようなもの)」をSQLの中に仕込んでおくことです。

—

ステップ2:VBAからQueryDef経由でパラメータを渡して実行する

検索ボタンがクリックされたときに走るVBAコードがこちらです。コピペしてそのまま使えますよ。

Private Sub btn検索_Click()
On Error GoTo ErrorHandler

Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset

‘ 1. データベースとQueryDefオブジェクトを取得する
Set db = CurrentDb
Set qdf = db.QueryDefs(“qry_案件検索_Base”)

‘ 2. フォームに入力された値をパラメータに安全にセットする
‘ ※ここで値を渡すことで、SQLインジェクションや構文エラーを防ぎます
qdf.Parameters(“prm案件名”) = Nz(Me.txt案件名.Value, “”)
qdf.Parameters(“prm担当者”) = Nz(Me.txt担当者.Value, “”)

‘ 3. パラメータを適用したクエリからレコードセットを開き、サブフォームに流し込む
‘ (※検索結果を表示するための「sfm結果」というサブフォームがあると仮定)
Set rst = qdf.OpenRecordset(dbOpenSnapshot)

‘ レコード数が0件の場合のハンドリング
If rst.RecordCount = 0 Then
MsgBox “該当するデータが見つかりませんでした。”, vbInformation, “検索結果”
End If

‘ サブフォームのレコードソースとして、このQueryDefを指定する
‘ (直接SQLを書くのではなく、名前を指定するのがミソ!)
Me.sfm結果.Form.RecordSource = “qry_案件検索_Base”

‘ 4. オブジェクトの解放(メモリリークを防ぐプロの作法)
rst.Close
Set rst = Nothing
Set qdf = Nothing
Set db = Nothing

Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
‘ エラー時も確実にメモリ解放を行う
If Not rst Is Nothing Then rst.Close: Set rst = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub

—

4. コードのここがスゴい!3つのポイント

初心者の方に向けて、このコードの優秀なポイントを解説します。

1. `Nz(…, “”)` でNullを華麗にガード
テキストボックスが空欄のまま検索されたとき、VBAでは `Null` という「何もない状態」になります。これをそのまま渡すとSQLがバグることがあるため、`Nz関数`で「空文字(`””`)」に変換して安全に処理しています。
2. SQLの文字列結合から解放される
「`”SELECT FROM … WHERE … & variable & …`」のような、ダブルクォーテーションの閉じ忘れやシングルクォーテーションの地獄から完全に解放されます。パラメータクエリを使うことで、Accessが自動的にデータの型を安全に解釈してくれます。
3. 確実なメモリ管理(オブジェクトの解放)
DAOの `Database`, `QueryDef`, `Recordset` は、使い終わったら必ず `Set xxx = Nothing` や `.Close` でメモリから解放してあげる必要があります。ここをサボらないのが、Accessアプリを重くしない(落ちなくする)チーフアーキテクトのこだわりです。

—

まとめ:ここをクリアすれば、Access VBAの基本はバッチリ!

いかがでしたでしょうか?
「フォームのレコードソースを直接書き換える」という泥臭い方法から、「QueryDefとパラメータを介して安全にデータを操る」というスマートな設計手法への移行。

このアプローチを身につければ、

  • マルチユーザー環境でもエラーが起きない
  • メンテナンス性が劇的に高い
  • 動作が軽快で安定した

そんなプロフェッショナルなAccessデータベースを構築できるようになります。

最初は少し難しく感じるかもしれませんが、一度この型を覚えてしまえば、どんな複雑な検索画面も怖くありません。ぜひ次の開発案件で試してみてくださいね。あなたのAccess開発ライフが、より快適で知的で楽しいものになることを応援しています!

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