こんにちは!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開発ライフが、より快適で知的で楽しいものになることを応援しています!
