Access VBAの「暗黒面」を断つ:動的SQLとワイルドカードの正しい作法
現場でよく見る「動的SQLの文字列結合」という名の爆弾。
`strSQL = “SELECT FROM T_Master WHERE Name LIKE ‘” & Me.txtSearch.Value & “‘”`
初心者が通る道とはいえ、この書き方は「バグの温床」かつ「セキュリティリスクの塊」です。
なぜこれがダメなのか。単にインジェクションのリスクだけではありません。
`’`(シングルクォート)が含まれた文字列が入力された瞬間にクエリは構文エラーで沈没し、運用保守のコストを跳ね上げます。
今日は、Access VBAで「堅牢かつ高速」な検索機能を実装するための、プロフェッショナルな解法を伝授します。
—
1. なぜ「文字列結合」を捨て、「Parameters」を使うべきか
Accessの `QueryDef` オブジェクトと `Parameters` コレクションを活用すれば、SQLの構文解析とデータのバインドを分離できます。
- 型安全: データ型を明示することで、予期せぬ型変換によるエラーを防ぐ。
- エスケープ不要: ユーザー入力内の特殊文字をSQL構文の一部として誤解させない。
- プランキャッシュの再利用: クエリの実行計画が固定されるため、大規模データではパフォーマンスが安定する。
—
2. 実装の極意:LIKE演算子とパラメータの融合
多くのエンジニアが躓くのが「パラメータにワイルドカードを含めるとうまく動かない」という点です。
SQL内で `LIKE ?` と書き、パラメータに `keyword` を渡しても、AccessのJET/ACEエンジンはこれを「リテラル(文字列そのもの)」として扱ってしまい、結果がゼロになります。
正解は、SQL側で `Like “” & [prm] & “”` と記述し、パラメータには純粋な検索ワードのみを渡すことです。
—
3. プロダクションコード:保守可能な検索実装
このコードは、エラーハンドリングを備え、再利用性を考慮した設計です。フォームの検索ボタン等に配置してください。
Public Sub ExecuteSecureSearch(ByVal keyword As String)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
On Error GoTo ErrorHandler
Set db = CurrentDb
‘ 既存のクエリ定義を再利用(または一時クエリを作成)
Set qdf = db.QueryDefs(“qry_MainSearch”)
‘ パラメータに値をセット(ワイルドカードはSQL側で処理する)
‘ SQL例: SELECT FROM T_Clients WHERE ClientName Like “” & [prmKeyword] & “”
qdf.Parameters(“prmKeyword”) = keyword
‘ レコードセットの取得
Set rs = qdf.OpenRecordset(dbOpenSnapshot)
‘ ここでフォームのレコードソースにセットするなどの処理を行う
‘ Set Me.Recordset = rs
Debug.Print “検索完了: ” & rs.RecordCount & ” 件ヒットしました。”
CleanUp:
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox “検索中にエラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub
このコードが「現場で勝てる」理由
1. DAOの明示的な解放: `Set qdf = Nothing` を徹底することで、メモリリークを確実に防ぎます。
2. `dbOpenSnapshot` の利用: 検索結果を編集しないのであれば、スナップショットを使うべきです。これは読み取り専用でオーバーヘッドが最小限に抑えられます。
3. 分離設計: SQLのロジックはクエリデザインウィンドウ(または定義文)に隠蔽し、VBA側はパラメータを流し込む「パイプ」に徹する。これが長期保守の鉄則です。
—
4. 運用時の注意点:クエリの生存期間
「動的SQLを生成して `QueryDef` を作成・削除する」という手法を好む人もいますが、私は推奨しません。
Accessの内部メタデータが断片化し、DBファイルが肥大化する原因になります。
- 推奨: あらかじめ名前付きクエリを作成しておき、`Parameters` を書き換える。
- 例外: 検索条件が動的に大幅に変化する場合のみ、`db.CreateQueryDef(“”, strSQL)` を使った一時クエリを作成すること。
まとめ
プロフェッショナルは「動くコード」ではなく「壊れないコード」を書きます。
`LIKE` 演算子とパラメータクエリを正しく組み合わせることで、あなたのAccessアプリは、ユーザーがどんな過激な文字列を検索窓に打ち込んでも、決して悲鳴を上げることはありません。
まずは、あなたの既存の検索ロジックを、この「パラメータバインド方式」へ書き換えてみてください。それだけで、コードの品格と安定性が一段上のステージへ昇華するはずです。
