【入門編】DAO.RecordsetのBatchUpdateを自作する:トランザクション管理による一括更新の高速化 – Access VBA解析バイブル

スポンサーリンク

こんにちは! 現場でバリバリとAccessやVBAを使っていると、ふとこんな壁にぶつかりませんか?

「なんだか、データの一括更新や保存処理にやたら時間がかかる……」
「画面がフリーズしたみたいになって、ユーザーから『遅い!』って怒られちゃった……」

そうなんです。Access VBAでよくやりがちなのが、画面のフォームやテーブルから「1レコードずつ丁寧に更新(`.Edit` して `.Update`)」していく方法。これ、実は裏でディスクへの書き込みや画面の再描画が何度も行われていて、プログラミングの世界ではパフォーマンスの「大罪」とも言える非効率な動きをしています。

今回は、ここをスパッと解決するための極意「トランザクション制御を使った自作BatchUpdate(一括更新)」を、優しく、かつ本質的なエンジニアの視点でお伝えしますね。

ここをクリアすれば、あなたの書くAccess VBAは一段も二段もレベルアップします。さあ、一緒に極限の高速化の世界を覗いてみましょう!

1. なぜ「1件ずつ更新」は遅いのか?(背景と原因)

まずは敵を知ることから始めましょう。

例えば、1,000件の売上データに「消費税率の改定」を反映させるとします。
何も考えずにループを回してこう書いたとしますよね。

‘ 【やってはいけない!遅い書き方の例】
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset(“T_Sales”, dbOpenDynaset)

Do Until rs.EOF
rs.Edit
rs.Fields(“TaxRate”).Value = 0.1 ‘ 書き換え
rs.Update ‘ ★ここで毎回ディスクに書きに行っちゃう!
rs.MoveNext
Loop
rs.Close

これ、何が起きているかというと、データベースの扉を1,000回開け閉めしているようなものなんです。1回ごとの処理はコンマ数秒でも、それが1,000回積もり積もると、数秒〜数十秒の「待たされる時間」になってしまいます。

救世主:トランザクション + メモリ上での一括処理

これを解決するのが「トランザクション(取引のまとまり)」「メモリ上での一括コミット」です。

イメージとしては、こうです:
1. 「今から一気にデータを書き換えるよ!」とデータベースに宣言する(トランザクションの開始)。
2. 作業は全部メモリ(PCの超高速な作業机)の上だけで猛スピードで行う。
3. 最後に「よし、全部終わったから一発で保存して!」とデータベースに伝える(コミット)。

これだけで、ディスクへのアクセスが最小限になり、処理速度が劇的に(場合によっては数十倍!)跳ね上がります。

2. 実装編:自作BatchUpdateコードの全貌

それでは、実際に現場でそのままコピペして使える、極上のサンプルコードをお見せします。
今回は「T_Sales(売上テーブル)」の特定の条件のデータを一括で書き換えるシナリオです。

‘ ==============================================================================
‘ モジュール名: 業務自動化モジュール
‘ 概要 : トランザクションを活用した高速一括更新(BatchUpdate)のサンプル
‘ ==============================================================================
Sub ExecuteHighSpeedBatchUpdate()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim startTime As Double

‘ 処理時間を計測するためのタイマー開始
startTime = Timer

‘ 現在のデータベース接続を取得
Set db = CurrentDb

‘ 1. 【極意その1】安全かつ高速なトランザクションの開始
‘ 万が一途中でエラーが起きても、ロールバック(なかったことに)できるようにします
db.BeginTrans
On Error GoTo ErrorHandler ‘ エラー時のトラップを仕掛けます

‘ 2. Recordsetを開く(今回は高速なテーブル直接操作: dbOpenTable)
Set rs = db.OpenRecordset(“T_Sales”, dbOpenTable)

‘ 3. メモリ上で一気呵成にループ処理を行う
With rs
Do Until .EOF
‘ 例:未処理のデータだけ金額を10%アップさせる
If !Status = “未処理” Then
.Edit ‘ 編集モードに入る(まだディスクには書きません)

‘ 値の書き換え
!Amount = !Amount 1.1
!Status = “処理済み”

.Update ‘ バッファ(メモリ)に確定させる
End If
.MoveNext
Loop
End With

‘ 4. 【極意その2】すべての変更を「一括(コミット)」して確定させる
db.CommitTrans

‘ 後片付け
rs.Close
Set rs = Nothing
Set db = Nothing

‘ 完了メッセージ
MsgBox “一括更新が完了しました! 処理時間: ” & Format(Timer – startTime, “0.00”) & “秒”, vbInformation, “高速化成功”
Exit Sub

ErrorHandler:
‘ エラーが発生した場合は、変更をすべてなかったことにする(ロールバック)
db.Rollback

‘ 後片付け
If Not rs Is Nothing Then
rs.Close
Set rs = Nothing
End If
Set db = Nothing

MsgBox “エラーが発生したため、処理を中断しました。” & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “トランザクション・ロールバック”
End Sub

3. コードの深い解説:なぜこれが速く、安全なのか?

初心者のうちは、「エラーが起きたときにどうなるか」が怖くてトランザクションを避けたくなりがちですが、ここを抑えるのが一流への第一歩です。

① `db.BeginTrans` と `db.CommitTrans` のコンビ

  • `db.BeginTrans`: 「ここから先の一連の変更は、すべてセットとして扱ってください」というデータベースへの予約です。
  • `db.CommitTrans`: 「ここまでの一連の作業が完璧に終わったので、データベースに正式に書き込んでください」という確定の合図です。

② 恐ろしいエラーからデータを守る `ErrorHandler`

もし、ループの途中で「ネットワークが切れた」「ディスク容量が足りなくなった」「0で割るエラーが起きた」というとき、1件ずつ更新していると、「途中まで書き換わった中途半端なデータ」がテーブルに残ってしまい、データが破損します。

しかし、トランザクションを組んでおけば、`Err.Description` に捕らえられた瞬間に `db.Rollback`(ロールバック)が走り、一連の変更がすべてきれいに無かったことになります。 これぞ、プロのエンジニアが絶対に取り入れるべき「安全性の担保」です。

4. 陥りやすい罠とアドバイス

ここで、実務でよくあるハマりポイントをいくつかシェアしておきますね。

  • 罠1: 開くレコードセットのタイプに気をつけよう

今回のコードでは `dbOpenTable` を使っています。これはテーブルを直接触るので一番速いですが、複雑なSQL(結合クエリなど)の場合は `dbOpenDynaset` を使ってください。用途に応じた適切なオブジェクト選択が命運を分かります。

  • 罠2: ループ中に画面を更新させない

大前提として、処理中は `DoCmd.Hourglass True`(砂時計カーソルにする)などでユーザーが余計なマウス操作をしないように配慮しましょう。余計なフォームの再描画走らせないことも高速化の秘訣です。

まとめ

いかがでしたでしょうか?
DAO.Recordsetのトランザクション管理を伴う一括更新(BatchUpdate)は、Access VBAの限界を突破し、実用に耐えうる堅牢でスピーディーなシステムを作るための強力な武器です。

「1件ずつチマチマ更新するコード」から卒業し、メモリとトランザクションを味方につけた「スマートな一括処理」をマスターすれば、あなたの作るAccessアプリは見違えるほど快適になりますよ。

ここをクリアしたあなたなら、もうAccess VBAの基礎はバッチリです!
ぜひ、実際の開発現場や身の回りのツールで試してみてくださいね。応援しています!

タイトルとURLをコピーしました