AccessのVBAでレコードをループ処理する方法【DAO Recordset入門】

access-vba-dao-recordset-loop Access

はじめに

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.EOFrs.MoveNextLoop が基本構造
  • 値の読み取りは rs!フィールド名
  • 値の変更は Edit → 代入 → Update
  • 処理後は必ず rs.Close でクローズ
  • 全件同一更新ならSQL UPDATEのほうが高速

1件ずつ異なる処理が必要な業務ロジックでは、Recordsetループは非常に強力な武器になります。ぜひ活用してみてください。

コメント

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