こんにちは! Access VBAの開発現場で、日夜データと格闘お疲れ様です。
今日は、Accessデータベースの信頼性を保つための「超・重要テクニック」についてお話ししますね。
マクロの記録から一歩踏み出し、VBAで本格的なデータ操作(INSERTやUPDATEなど)を行うようになると、避けて通れないのが「エラーとの向き合い方」です。
「ここをクリアすれば、Access VBAの基本はバッチリですよ!」と言えるほど大切な、DAOの真髄`dbFailOnError`について、シニアエンジニアの視点から魂を込めて解説します。
—
1. なぜ「静かに失敗する」SQLは恐ろしいのか?
VBAからSQL文を実行するとき、皆さんはどんな方法を使っていますか?
多くの入門書では、次のようなコードが紹介されているはずです。
‘ よくある実行コード
CurrentDb.Execute “UPDATE T_受注台帳 SET ステータス = ‘完了’ WHERE 注文ID = 9999”
一見、何の問題もないように見えますよね。
でも、プロの現場では、この書き方は「爆弾を抱えている」とみなされます。
なぜなら、この `CurrentDb.Execute` というメソッド、デフォルトでは「途中でエラーが起きようが、データが更新できなかろうが、知らん顔してスルーする」という仕様になっているからです。
例えば:
- 更新しようとしたレコードが、別のユーザーにロックされていた
- 外部キー制約(リレーションシップ)に違反するデータを書き込もうとした
- フィールドの型エラーや、文字数オーバーが発生した
こんな時でも、`dbFailOnError` を指定しないと、エラーメッセージすら出さずに「平然と次の行のコードへ進んでしまう」のです。気がついた時には、データベースの一部だけが書き換わり、全体のデータ整合性が崩れ去っている……。これが、実務で最も恐ろしい「サイレントエラー」の正体です。
—
2. 救世主 `dbFailOnError` の正体と仕組み
この恐怖の「サイレントエラー」を撃退し、データベースの秩序を守る騎士こそが、今回テーマにする `dbFailOnError` オプションです。
使い方は極めてシンプル。`Execute` メソッドの第2引数に、この定数をポンと追加するだけです。
CurrentDb.Execute “UPDATE T_受注台帳 SET ステータス = ‘完了’ WHERE 注文ID = 9999”, dbFailOnError
たったこれだけ?と思われるかもしれませんが、効果は絶大です。
このオプションを付与すると、DAOは次のような挙動に変わります。
1. トランザクションの保護: SQLの実行中に1件でもエラーが発生した場合、その実行は即座に中断されます。
2. ロールバックの保証: 途中で失敗した場合、そのSQL文で行われた変更は「なかったこと(元の状態)」に自動的に巻き戻されます。中途半端なデータが残ることは絶対にありません。
3. エラーの発生: VBA側で実行時エラー(トラップ可能なエラー)が発生するため、`Err` オブジェクトで確実に検知できます。
—
3. 実践!安全なトランザクション制御コード
それでは、実際の開発現場でそのままコピペして使える、堅牢(ロバスト)なエラーハンドリング付きのコードパターンを見てみましょう。
Sub UpdateOrderStatusSafe()
On Error GoTo ErrorHandler ‘ エラー発生時のジャンプ先を指定
Dim strSQL As String
strSQL = “UPDATE T_受注台帳 SET ステータス = ‘完了’ WHERE 処理フラグ = 0”
‘ dbFailOnError を付与して実行
CurrentDb.Execute strSQL, dbFailOnError
MsgBox “データの更新が正常に完了しました!”, vbInformation, “成功”
Exit Sub
ErrorHandler:
‘ 万が一エラーが発生した場合の処理
MsgBox “データの更新に失敗しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“内容: ” & Err.Description, vbCritical, “致命的エラー”
‘ ここでログ出力や追加のロールバック処理を行うことも可能
End Sub
このコードの美しいポイント
- データの不整合を防ぐ: もし1000件のデータを更新する途中で999件目でエラーが起きても、1件目から998件目までの変更が勝手に保存されてしまうことはありません。すべてが安全にロールバックされます。
- ユーザーへの親切なフィードバック: 「何が起きたのか分からない」という最悪の状況を回避し、エラー内容を正確にユーザー(または自分自身)に伝えることができます。
—
4. チーフアーキテクトからの実践アドバイス
最後に、より高度な開発を目指すあなたへ、ワンランク上の知見を授けます。
`CurrentDb.Execute` は非常に強力ですが、もし「複数の異なるテーブルに対して、一連のINSERTやUPDATEをセットで行い、どれか一つでも失敗したら全体をキャンセルしたい」という場合は、`CurrentDb.Execute` 単体では不十分です。
その場合は、次のように `Workspace` オブジェクトを使った本格的なトランザクション(BeginTrans / CommitTrans / Rollback)と `dbFailOnError` を組み合わせるのが、Access開発の最高峰のテクニックとなります。
Sub AdvancedTransactionSample()
Dim ws As DAO.Workspace
Set ws = DBEngine.Workspaces(0)
On Error GoTo TransactionError
‘ トランザクション開始
ws.BeginTrans
‘ 1つ目の処理
ws.Databases(0).Execute “UPDATE T_在庫 先生… (省略)”, dbFailOnError
‘ 2つ目の処理
ws.Databases(0).Execute “INSERT INTO T_履歴 … (省略)”, dbFailOnError
‘ すべて成功したらコミット(確定)
ws.CommitTrans
MsgBox “全トランザクションが成功しました。”, vbInformation
Exit Sub
TransactionError:
‘ 失敗したらロールバック(全取り消し)
ws.Rollback
MsgBox “エラーが発生したため、すべての変更をキャンセルしました。” & vbCrLf & Err.Description, vbCritical
End Sub
—
まとめ
- `CurrentDb.Execute` を使うときは、必ず `dbFailOnError` をセットで書く ことをコーディングの習慣にしましょう。
- デフォルトのままだと、エラーが起きてもデータが中途半端に壊れる「サイレントエラー」の罠にハマります。
- しっかりとエラーを検知し、データベースの健全性を保つプログラミングを身につければ、あなたの作るAccessアプリの信頼性は劇的に向上します。
基本をマスターした今、あなたはもう「マクロの記録者」ではありません立派な「Access VBAエンジニア」です。ぜひ、今日からのコードに取り入れてみてくださいね!
