はじめに
Accessでデータを1件ずつ処理したい場面は多くあります。
- 全レコードに対して計算処理を行いたい
- 条件に合うレコードだけ値を書き換えたい
- 処理結果を別テーブルに1件ずつ書き出したい
こういった「繰り返し処理」を実現するのが、VBAの Recordsetループ です。
この記事では、DAO Recordsetを使ったループ処理の基本から、よくある使いどころまでを実用的なコードで解説します。
DAO Recordsetとは
AccessのVBAでレコードを操作する仕組みには DAO(Data Access Objects) と ADO(ActiveX Data Objects) の2種類があります。
Accessで使う場合は DAOを選んでください。AccessはDAOとの親和性が高く、コードもシンプルになります。
基本構造:レコードを順番に処理する
Public Sub LoopRecords()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("テーブル名")
Do Until rs.EOF
' ここに処理を書く
Debug.Print rs!フィールド名
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
構造のポイント
| 行 | 役割 |
|---|---|
OpenRecordset | テーブルまたはクエリからレコードセットを開く |
Do Until rs.EOF | レコードの末尾(EOF)に達するまでループ |
rs!フィールド名 | 現在のレコードのフィールド値を取得 |
rs.MoveNext | 次のレコードに移動 |
rs.Close | 処理後は必ずクローズ |
注意:
rs.MoveNextを忘れると無限ループになります。必ずループ内の最後に記述してください。
レコードの値を読み取る
フィールドの値を取得するには rs!フィールド名 または rs("フィールド名") を使います。
Do Until rs.EOF
Dim strName As String
Dim lngAge As Long
strName = rs!氏名
lngAge = rs!年齢
Debug.Print strName & ":" & lngAge & "歳"
rs.MoveNext
Loop
どちらの書き方でも動作しますが、rs!フィールド名 のほうが入力補完が効くため実務では使いやすいです。
レコードの値を書き換える
値を変更するには Edit → 値を代入 → Update の順で記述します。
Public Sub UpdateRecords()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("テーブル名", dbOpenDynaset)
Do Until rs.EOF
rs.Edit
rs!ポイント = rs!ポイント + 10
rs.Update
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
MsgBox "更新完了しました。", vbInformation
End Sub
更新時のポイント
OpenRecordsetの第2引数にdbOpenDynasetを指定する(更新可能なレコードセットタイプ)rs.Editを呼ばずに値を代入するとエラーになるrs.Updateを忘れると変更が保存されない
条件付きループ:特定のレコードだけ処理する
WHERE句付きのSQLでレコードセットを絞り込めます。
Public Sub UpdateActiveOnly()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
strSQL = "SELECT * FROM 顧客テーブル WHERE ステータス = '有効'"
Set db = CurrentDb
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
Do Until rs.EOF
rs.Edit
rs!最終確認日 = Date
rs.Update
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
全件取得してIf文で分岐するより、最初からSQLで絞り込むほうが処理が速く、コードもシンプルになります。
エラー処理を組み込んだ実用コード
Public Sub LoopWithErrorHandling()
Dim db As DAO.Database
Dim rs As DAO.Recordset
On Error GoTo ErrorHandler
Set db = CurrentDb
Set rs = db.OpenRecordset("テーブル名", dbOpenDynaset)
Do Until rs.EOF
rs.Edit
rs!処理済みフラグ = True
rs.Update
rs.MoveNext
Loop
MsgBox "処理が完了しました。", vbInformation
Cleanup:
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました:" & Err.Description, vbCritical
Resume Cleanup
End Sub
Cleanup ラベルを使うことで、正常終了・エラー終了どちらの場合も必ず rs.Close が実行されます。Recordsetを閉じ忘れるとメモリリークやロックの原因になるため、この構造は重要です。
ループ処理 vs SQL一括更新:どちらを使うべきか
「全件更新」が目的の場合、ループより SQL UPDATE文のほうが圧倒的に速いです。
| 方法 | 速度 | 向いているケース |
|---|---|---|
| Recordsetループ | 遅い(件数に比例) | 1件ごとに異なるロジックが必要な場合 |
| SQL UPDATE | 速い(件数によらない) | 同じ値や単純な計算で全件・条件付き更新する場合 |
「全員のポイントを+10する」ならSQL、「1件ずつ複雑な計算をして書き込む」ならループ、と使い分けてください。
まとめ
DAO Recordsetを使ったループ処理の基本をまとめます。
Do Until rs.EOF~rs.MoveNext~Loopが基本構造- 値の読み取りは
rs!フィールド名 - 値の変更は
Edit→ 代入 →Update - 処理後は必ず
rs.Closeでクローズ - 全件同一更新ならSQL UPDATEのほうが高速
1件ずつ異なる処理が必要な業務ロジックでは、Recordsetループは非常に強力な武器になります。ぜひ活用してみてください。

コメント