こんにちは!Access VBAの開発現場で、日々奮闘していませんか?
マクロの記録から一歩踏み出し、「自分でコードを書いてシステムを動かしたい!」と思ったとき、最初に立ちはだかる大きな壁が「エラー(例外)」ですよね。
特に、VBAからデータベースの頭脳である「クエリ(QueryDef)」を動かすとき、SQLのちょっとした書き間違いや、データの競合で突然コードが止まってしまう……。黒い画面や見慣れないダイアログが出てくると、冷や汗が出てしまいます。
でも、安心してください。
プロのエンジニアにとって、エラーとは「敵」ではなく、「次にどう動けばいいかを教えてくれる親切なガイド」なんです。
今回は、QueryDef(クエリ定義)を使った動的なSQL実行時に起こるエラーを優しく、かつ確実に手なずけるための「例外ハンドリング設計」の極意を伝授します。ここをクリアすれば、あなたの書くAccess VBAは見違えるほどプロっぽく、そして強靭になりますよ!
—
1. なぜQueryDefのエラーハンドリングが必要なのか?
まずは、私たちが普段やりがちな「危ういコード」から見てみましょう。
‘ 【やってはいけない】エラー対策ゼロの危険なコード
Sub RunQueryUnsafe()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = CurrentDb
Set qdf = db.QueryDefs(“qry_MonthlySales”)
‘ パラメータを書き換えて実行!
qdf.Parameters(“prmDate”) = #2023/10/01#
qdf.Execute dbFailOnError ‘ ←ここでエラーが起きたら…?
MsgBox “処理が完了しました!”, vbInformation
End Sub
このコード、一見すると問題なさそうですが、実務では「大爆発」するリスクを秘めています。
もしここで、SQLの構文エラーがあったり、外部接続がタイムアウトしたり、主キーの重複エラー(エラー番号:3022など)が発生するとどうなるでしょうか?
VBAの実行は容赦なく強制終了し、ユーザーには意味不明な「実行時エラー ‘3022’: …」という冷たいダイアログが突きつけられます。ユーザーはパニックになり、ファイルは半端な状態でロックされる……最悪のシナリオですね。
これを防ぐのが、例外ハンドリング(エラー処理構文:`On Error`)です。
—
2. エラーハンドリングの基本構造:VBAの「安全ネット」
VBAには、エラーが発生したときにコードを強制終了させず、別のルートに避難させる仕組みが用意されています。それが `On Error GoTo` です。
図解的に表すと、コードの流れはこうなります。
[ 通常ルート ]
コード実行 ──> エラー発生! ──> (通常ルート中断)
│
▼
[ 避難ルート (ErrorHandler) ]
・エラーログの記録
・ユーザーへの優しいメッセージ
・後始末 (メモリ解放)
この仕組みを組み込んだ、実用的なQueryDef実行テンプレートを見てみましょう。
—
3. 実践!堅牢なQueryDef実行プロシージャ
開発現場でそのままコピペして使える、極限まで洗練されたサンプルコードです。丁寧なコメントを入れているので、一つずつ意味を噛み砕いていきてくださいね。
‘ =================================================================
‘ メソッド名: SafeExecuteQueryDef
‘ 概要 : パラメータ付きQueryDefを安全に実行し、エラーを優しくハンドリングする
‘ =================================================================
Public Sub SafeExecuteQueryDef()
‘ 1. 変数の宣言(DAOオブジェクト)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
‘ 2. エラーハンドラへのジャンプ指令をセット
On Error GoTo ErrorHandler
‘ 3. データベースとクエリの取得
Set db = CurrentDb
Set qdf = db.QueryDefs(“qry_UpdateInventory”)
‘ 4. 動的パラメータの設定
qdf.Parameters(“prmTargetDate”) = Date
qdf.Parameters(“prmStatus”) = “準備中”
‘ 5. クエリの実行(dbFailOnErrorを指定することで、途中の失敗を検知)
qdf.Execute dbFailOnError
‘ 6. 正常終了時の処理
MsgBox “在庫データの更新が正常に完了しました。”, vbInformation, “処理成功”
CleanUp:
‘ 7. オブジェクトの解放(メモリリークを防ぐプロの作法)
Set qdf = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
‘ =============================================================
‘ ここがエラーを味方につける「避難ルート」です
‘ =============================================================
Select Case Err.Number
Case 3022
‘ 主キー重複などの一意性制約エラー
MsgBox “すでに登録済みのデータと重複しているため、更新できません。” & vbCrLf & _
“入力内容を確認してください。”, vbExclamation, “重複エラー”
Case 3061
‘ パラメータが見つからない、またはスペルミスがあるエラー
MsgBox “クエリのパラメータ設定にシステムエラーが発生しました。” & vbCrLf & _
“管理者にお問い合わせください。(Error: ” & Err.Number & “)”, vbCritical, “設定エラー”
Case Else
‘ その他の予期せぬエラー
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“【エラー番号】: ” & Err.Number & vbCrLf & _
“【内容】: ” & Err.Description, vbCritical, “システムエラー”
End Select
‘ エラー処理後も必ず後始末ルートを通る
Resume CleanUp
End Sub
—
4. コードの深掘り解説:ここがエンジニアのこだわりポイント!
初心者の方からよく「なんでこんな書き方をするの?」と質問を受けるポイントを、優しく解説しますね。
① `dbFailOnError` は絶対につけよう!
DAOの `Execute` メソッドを使うとき、この引数を忘れる人が多いです。
これを付けないと、SQLの途中でエラー(例えば、数値を入れるべきところに文字が入ったなど)が起きたとき、「エラーが起きたことすら気づかずに、中途半端な状態で処理が成功したフリをして進んでしまう」という最悪のバグ(サイレントエラー)を引き起こします。
`dbFailOnError` を指定することで、失敗した瞬間に必ずエラーを発生させ、安全ネット(ErrorHandler)に飛び込ませることができます。
② `Select Case Err.Number` でエラーを仕分ける
すべてのエラーに対して「エラーが起きました」と出すのは、親切ではありません。
- 「入力ミスかもしれないエラー」なら、ユーザーに「ここ直してね」と優しく伝える。
- 「システム的な異常」なら、エラー番号を添えて開発者に連絡してもらう。
このように、エラーの「背番号(`Err.Number`)」を見て対応を変えるのが、ワンランク上のエラーハンドリング設計です。
③ `CleanUp:` ラベルと `Resume CleanUp` による確実な後始末
Access VBAで忘れがちなのが、メモリの解放(`Set qdf = Nothing`)です。
エラーが起きて途中でコードが中断されると、メモリ上にオブジェクトが残り続け、Accessが重くなったりフリーズしたりする原因になります。
エラーが起きた場合でも、正常に終わった場合でも、必ず `CleanUp` ラベルを通る構造(サーキットブレーカーのような仕組み)にしておくことが、安定稼働するシステムの絶対条件です。
—
まとめ:エラーは「親切なアドバイザー」
いかがでしたでしょうか?
QueryDefの実行におけるエラーハンドリングは、最初は少し難しく感じるかもしれませんが、パターンは決まっています。
1. `On Error GoTo ErrorHandler` で安全ネットを張る
2. `dbFailOnError` でエラーを取りこぼさないようにする
3. `Err.Number` でエラーの種類に応じた優しいメッセージを返す
4. `CleanUp` でメモリをキレイに掃除して終わる
この4ステップさえマスターすれば、もう黒いエラー画面に怯える必要はありません。エラーを味方につけて、ユーザーから「おっ、このシステム使いやすいな!」と言われるような、ワンランク上のAccessアプリを作っていきましょう。
ここをクリアできれば、あなたのVBAスキルはもう初級者卒業です。自信を持って次のステップへ進んでくださいね!
