こんにちは!Access VBAの開発現場で、日々頭を悩ませていませんか?
「画面の入力値をもとに動的にSQLを組み立てて実行したら、なんかよく分からないエラーで止まった……」
「ユーザーから『突然エラー画面が出たんだけど!』と怒られてしまった……」
うんうん、よくあることですね。マクロの記録から脱却し、自分の手でSQLを組み立ててデータを自在に操り始めると、誰もが一度は通る壁です。
でも、安心してください。今回お伝えする「QueryDefを使った事前バリデーション(構文チェック)」の技を手に入れれば、あなたもワンランク上のエンジニアへ一気に駆け上がることができます。
ここをクリアすれば、Access VBAの基本はバッチリですよ。さあ、一緒に本質を学んでいきましょう!
—
なぜ、実行時エラーは「事後」にやってくるのか?
私たちがVBAで動的SQL(文字列として組み立てたSQL)を実行するとき、通常はこんなコードを書きますよね。
‘ 良くある動的SQLの実行
Dim sql As String
sql = “SELECT FROM T_売上 WHERE 顧客ID = ” & Me.txtID & ” AND 処理月 = ‘” & Me.txtMonth & “‘”
CurrentDb.Execute sql, dbFailOnError
このコード、一見何の問題もなさそうです。しかし、もしユーザーが入力ミスをしたり、未入力のままボタンを押したりして、SQLが以下のような変な形になってしまったらどうでしょう?
> `SELECT FROM T_売上 WHERE 顧客ID = AND 処理月 = ‘202310’`
> (`=` の後ろに値がないので、構文エラー!)
この時、Accessは親切にこう叫びます。
「実行時エラー ‘3141’: FROM 句の構文エラーです。」
画面の前で固まるユーザー。原因が分からないあなた。
これ、ものすごく不親切ですよね。エラーが起きてから慌てて止めるのではなく、「実行する前に、そのSQL、本当に正しい?」とAccess自身に検問させてしまえばいいのです。
—
秘儀:QueryDefを使った「SQLの事前検問」
DAO(Data Access Objects)には、一時的にクエリ定義(QueryDef)オブジェクトを作成し、それをデータベースに登録せずに「構文だけをチェックさせる」という裏技があります。
正確には、一時的なQueryDefを作ってパラメータをバインド、あるいはSQLを設定した瞬間の構文解析を利用するアプローチです。
今回は、実務でそのままコピペして使える「SQL構文の事前バリデーション関数」を用意しました。
実装コード:一歩先を行く安全なSQL実行モジュール
以下のコードを標準モジュールに貼り付けてみてください。
Option Explicit
‘ ==============================================================================
‘ 概要: 動的SQLの構文を事前に検証し、安全に実行するプロシージャ
‘ ==============================================================================
Public Sub SafeExecuteDynamicSQL()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strSQL As String
On Error GoTo ErrorHandler
Set db = CurrentDb
‘ 1. 動的SQLの組み立て(例:画面のフォームから値を取得して構築)
‘ ※ここでは意図的にエラーになりやすい組み立てを想定しています
strSQL = “SELECT FROM T_顧客マスタ WHERE 顧客ID = ” & Nz(Me.txtCustomerID, “0”)
‘ ==========================================================================
‘ 2. 事前バリデーション(QueryDefによる構文チェックの魔術)
‘ ==========================================================================
‘ まだデータベースに保存しない「一時的なQueryDef」を作成します(名前を空欄にする)
Set qdf = db.CreateQueryDef(“”, strSQL)
‘ ここまでエラーなく通過できれば、SQLの構文(Syntax)は完全に正しい!
‘ 3. 本番実行(QueryDefオブジェクト経由で安全に実行)
‘ Executeメソッドを使うことで、トランザクションやエラー制御が確実になります。
qdf.Execute dbFailOnError
MsgBox “SQLの実行が正常に完了しました!”, vbInformation, “成功”
CleanExit:
‘ 4. オブジェクトのクリーンアップ(メモリリークを絶対に防ぐプロの作法)
If Not qdf Is Nothing Then
‘ 一時QueryDefは明示的に閉じる・破棄する
qdf.Close
Set qdf = Nothing
End If
Set db = Nothing
Exit Sub
ErrorHandler:
‘ 5. ユーザーフレンドリーなエラーハンドリング
MsgBox “SQLの構文に誤りがあるか、実行時エラーが発生しました。” & vbCrLf & _
“【エラー詳細】: ” & Err.Description & vbCrLf & _
“【生成されたSQL】: ” & vbCrLf & strSQL, _
vbCritical, “事前バリデーション検知エラー”
Resume CleanExit
End Sub
—
コードの注目ポイント(プロのこだわり)
初心者から一歩抜け出すために、このコードに隠された「3つの美学」を解説します。
1. `db.CreateQueryDef(“”, strSQL)` の強力さ
第一引数に空文字 `””` を渡すと、Accessの「ナビゲーションウィンドウ(左側のオブジェクト一覧)」を汚すことなく、メモリ上だけに一時的なクエリ定義を作ることができます。
この瞬間、Accessのデータベースエンジン(Jet/ACE)がSQLの構文解析(パース)を走らせます。もし構文がおかしければ、この行で即座に `ErrorHandler` へジャンプします。つまり、「実際にデータを破壊したり重い処理を走らせる前に、0.1秒で嘘を見抜く」ことができるのです。
2. メモリリークを許さない「CleanExit」パターン
Access VBAで最も多いトラブルの一つが「メモリの解放漏れ」です。`Set qdf = Nothing` や `Set db = Nothing` をサボると、Accessの動作が徐々に重くなり、やがてフリーズの原因になります。
どんなにエラーが起きようとも、必ず `CleanExit` ラベルを通る構造(`On Error GoTo` からの `Resume`)にすることで、リソースを綺麗に掃除して帰る。これがプロの作法です。
3. デバッグ情報の親切な提供
エラーメッセージの中に「実際に生成されたSQL」を載せている点に注目してください。
「何が原因でSQLがおかしくなったのか」がひと目で分かるため、開発時も運用時も、トラブルシューティングの時間が圧倒的に短縮されます。
—
陥りやすい罠:文字列結合の悪夢
動的SQLを作る際、初心者が一番やってしまうのが「ダブルクォーテーション(”)とシングルクォーテーション(’)の迷子」です。
例えば、テキストボックスの値を条件にするとき:
‘ 危険な書き方(日付や文字列のクォーテーション忘れ)
strSQL = “SELECT FROM T_履歴 WHERE 担当者 = ” & Me.txtStaff
もし `txtStaff` に「田中」と入っていたら、生成されるSQLは `SELECT FROM T_履歴 WHERE 担当者 = 田中` となり、SQL側は「田中」という名前のフィールドを探しにいってエラーになります。正しくは `’田中’` とシングルクォーテーションで囲まなければなりません。
今回紹介した 「QueryDefによる事前バリデーション」 を組み込んでおけば、こうしたクォーテーションの付け忘れや、カンマの数ミスといった「構文上のミス」を、ユーザーに迷惑をかける前に100%キャッチできます。
—
まとめ
Access VBAにおける動的SQLの生成は、諸刃の剣です。強力で柔軟な反面、一歩間違えればバグの温床になります。
- エラーが起きてから慌てない。
- `CreateQueryDef` を使って、実行前にAccess自身に検問させる。
- リソースの解放(後片付け)を徹底する。
この3つを意識するだけで、あなたの書くコードの信頼性はプロのレベルへと劇的に跳ね上がります。
「動かないプログラムをいじり倒す時間」から卒業し、「スマートに安全な仕組みを構築するエンジニア」へ。
今日の学びを、ぜひ明日の開発現場で試してみてくださいね。応援しています!
