AccessのマクロやDoCmdで基本的なフォーム操作はできるようになったけれど、「フォームを開かずにVBAだけでレコードを追加・更新・削除したい」「条件に合うレコードを検索してフィールド値を書き換えたい」という場面が出てきます。そこで活躍するのがDAO(Data Access Objects)Recordsetです。
本記事ではDAO Recordsetの基本構文から、AddNew(追加)・Edit(更新)・Delete(削除)・FindFirst(検索)の4つの操作を実践的なコード例とともに解説します。AccessのVBAを一歩先へ進めたい方に向けた実践入門です。

DAO Recordsetとは何か
DAO(Data Access Objects)は、AccessのVBAからJetエンジン(Accessの組み込みデータベースエンジン)を操作するためのオブジェクトモデルです。Recordset(レコードセット)は、テーブルやクエリの結果をVBA内で「カーソル」として扱うオブジェクトで、プログラムからレコードを1件ずつ読み書きできます。
DoCmdと比較したときのDAO Recordsetの主な利点は次のとおりです。
- フォームを開かずにテーブルを直接操作できる
- ループ処理で複数レコードを一括変更できる
- 条件を絞ってピンポイントで検索・書き換えができる
- トランザクション(BeginTrans/CommitTrans)と組み合わせてロールバックができる
DAOを使う前の準備:参照設定の確認
VBEで初めてDAOを使うときは参照設定が必要です。AccessはデフォルトでDAO参照が有効な場合がほとんどですが、念のため確認しましょう。
- VBEを開く(Alt + F11)
- メニューの「ツール」→「参照設定」をクリック
- 「Microsoft DAO 3.6 Object Library」にチェックが入っているか確認
- チェックがなければ付けて「OK」をクリック
ADO(ActiveX Data Objects)という別のオブジェクトモデルもありますが、Accessの組み込みテーブル・クエリに対してはDAOのほうがシンプルで動作も安定しています。本記事はDAO前提で解説します。
Recordsetを開く・閉じる基本構文
DAOでRecordsetを使うときの基本構造は次のとおりです。変数の宣言・Recordsetのオープン・操作・クローズの4段階が基本セットになります。
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("T_受注", dbOpenDynaset)
' ここで操作 '
rs.Close
Set rs = Nothing
Set db = Nothing
dbOpenDynasetは「追加・更新・削除が可能なカーソル」を意味します。読み取りだけなら dbOpenSnapshot を使うと処理が軽量になります。
| 定数 | 説明 |
|---|---|
| dbOpenDynaset | 追加・更新・削除が可能 |
| dbOpenSnapshot | 読み取り専用・高速 |
| dbOpenTable | テーブル直接アクセス(クエリには使用不可) |
全レコードをループ処理する(EOF/BOF)
Recordsetのすべてのレコードを順番に処理するには Do Until rs.EOF のループを使います。EOFはEnd of Fileの略で、最後のレコードを過ぎたときにTrueになります。
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("T_受注", dbOpenDynaset)
Do Until rs.EOF
Debug.Print rs!受注ID & " : " & rs!顧客名
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
rs.MoveNextを忘れると無限ループになります。ループの末尾に必ず書くことを習慣にしましょう。フィールドの参照は rs!フィールド名 または rs("フィールド名") の2通りの書き方があります。
レコードを追加する(AddNew・Update)
新しいレコードを追加するには AddNew で空のレコードを用意し、各フィールドに値をセットしてから Update で保存します。
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("T_受注", dbOpenDynaset)
rs.AddNew
rs!顧客名 = "株式会社○○" ' 想定例 '
rs!受注日 = Date()
rs!金額 = 50000 ' 想定例 '
rs.Update
rs.Close
Set rs = Nothing
Set db = Nothing
MsgBox "レコードを追加しました。"
AddNewとUpdateはセットで使います。Updateを呼ばないと変更がキャンセルされてテーブルには何も保存されません。フォームの「保存」ボタンに相当するのがUpdateです。
オートナンバー型のフィールド値を取得するには
追加したレコードのオートナンバー値(主キー)を直後に取得したい場合は、UpdateのあとにLastModifiedプロパティを使います。
rs.AddNew
rs!顧客名 = "株式会社△△" ' 想定例 '
rs.Update
rs.Bookmark = rs.LastModified
Debug.Print "新規受注ID: " & rs!受注ID
レコードを更新する(Edit・Update)
既存のレコードを書き換えるには Edit で編集モードに入り、フィールドを書き換えて Update します。
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("T_受注", dbOpenDynaset)
Do Until rs.EOF
If rs!ステータス = "未確認" Then
rs.Edit
rs!ステータス = "確認済"
rs.Update
End If
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
条件に合うレコードだけを更新する場合はIf文と組み合わせます。なお、同じ処理をSQL UPDATE文で実装できる場合は db.Execute "UPDATE T_受注 SET ステータス='確認済' WHERE ステータス='未確認'" のほうがシンプルになります。用途に応じて使い分けましょう。
レコードを削除する(Delete)
現在のカーソルが指すレコードを削除するには Delete を呼びます。AddNew・Editと異なり、Deleteの後にUpdateは不要です。
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("T_仮登録", dbOpenDynaset)
Do Until rs.EOF
If rs!登録日 < DateAdd("d", -30, Date()) Then
rs.Delete
End If
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
重要:Delete後もrs.MoveNextが必要です。削除後のカーソルは削除済みレコードを指したままになるため、MoveNextで次のレコードへ進めないとEOFが正常に判定されません。
レコードを検索する(FindFirst・FindNext)
条件を指定して最初の一致レコードを見つけるには FindFirst、次の一致レコードへ進むには FindNext を使います。
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb()
Set rs = db.OpenRecordset("T_受注", dbOpenDynaset)
rs.FindFirst "顧客ID = 101" ' 想定例 '
If rs.NoMatch Then
MsgBox "該当レコードはありません。"
Else
MsgBox "顧客名: " & rs!顧客名
End If
rs.Close
Set rs = Nothing
Set db = Nothing
rs.NoMatch はFindFirstで一致がなかったときにTrueになります。必ずNoMatchを確認してからフィールドを参照しましょう。NoMatchのまま参照するとエラーが発生します。
FindFirst条件式の型別の書き方
| フィールドのデータ型 | 条件式の例 |
|---|---|
| 数値型 | “顧客ID = 101” |
| テキスト型 | “都市名 = ‘東京'”(シングルクォートで囲む) |
| 日付/時刻型 | “受注日 = #2026/01/01#”(#記号で囲む) |
| Yes/No型 | “完了フラグ = True” |
FindFirst・FindNextを組み合わせた全件検索
rs.FindFirst "区分 = '優先'" ' 想定例 '
Do Until rs.NoMatch
Debug.Print rs!受注ID
rs.FindNext "区分 = '優先'"
Loop
よくあるつまずきと対処法
「現在のレコードセットは更新できません」エラー
クエリをRecordsetとして開くとき、複数テーブルの結合を含んでいると更新できない場合があります。対処法は、単一テーブルを直接開くか、必要なフィールドだけを含む更新可能なクエリに変更することです。
「項目が見つかりません」エラー
フィールド名のスペルミスが多い原因です。rs!フィールド名 と rs("フィールド名") のどちらでも参照できますが、rs("フィールド名") のほうがエラーメッセージがわかりやすい傾向があります。テーブルのフィールド名をコピー&ペーストして確認しましょう。
MoveNextを忘れた無限ループ
Do Untilループの中でDeleteやIf分岐のみ実行してMoveNextを書き忘れると無限ループになります。VBEの「実行」メニュー→「リセット」でループを強制停止できます。ループ末尾のMoveNextは最初に書いてしまう習慣をつけると防止できます。
参照設定が消えてしまう
DAO参照が外れると「ユーザー定義型は定義されていません」エラーになります。VBE→ツール→参照設定で再度確認してください。Accessのバージョンアップ後に外れることがあります。
MOS Access試験とDAO Recordsetの関係
MOS Access 365試験(MO-500)の出題範囲はテーブル設計・クエリ・フォーム・レポート・マクロが中心です。DAO RecordsetのようなVBAプログラミングは試験の直接の出題対象ではありません。
ただし、MOS Access取得後に実業務でデータベースを活用していくと、VBAでのRecordset操作は欠かせないスキルになります。毎月のデータ取込・更新作業の自動化、フォームから入力された値で複数テーブルをまとめて更新するといった場面で本記事の知識が直接役立ちます。

まとめ:DAO Recordset操作4つのパターン早見表
| 操作 | 使うメソッド | Updateの要否 |
|---|---|---|
| 追加 | AddNew → フィールド代入 → Update | 必要 |
| 更新 | Edit → フィールド代入 → Update | 必要 |
| 削除 | Delete → MoveNext | 不要 |
| 検索 | FindFirst → NoMatch確認 → フィールド参照 | 対象外 |
DAOの操作は一つずつ小さなモジュールで試して動作を確認してから組み合わせていくのが習得の近道です。VBEの「イミディエイトウィンドウ」(Ctrl + G)でDebug.Printの出力を確認しながら進めましょう。AccessのVBAはマクロでは届かない自由度を与えてくれます。
PR
たった1秒で仕事が片づくExcel自動化の教科書【改訂第3版】
Excel VBAの考え方はAccessのVBAにも通じる部分が多い一冊。ループ処理・条件分岐・データ操作の基本的な発想を体系的に学びたい方に。VBAで業務自動化に取り組む際の土台づくりに役立ちます。
AccessのVBAをさらに学ぶ
AccessのVBA入門(DoCmd・MsgBox・変数宣言)やフォームのイベントプロシージャ(OnLoad・AfterUpdate)の記事も合わせてご覧ください。
