こんにちは!Access VBAの世界へようこそ。
ここまでマクロや基本のコードを覚えて、「よし、いよいよ本格的なデータベースアプリを作るぞ!」と意気込んでいるあなたへ、今日はエンジニアとしての視界がパーッと広がるような、とっておきのテクニックを授けましょう。
テーマは「ADOの切断型レコードセット(Disconnected Recordset)」です。
「切断? レコードセット? なんだか難しそう……」と思ったかもしれませんが、大丈夫。ここをクリアすれば、あなたのAccess VBAのスキルは一気にワンランク上のステージに到達します。一緒に優しく、深く、本質に迫っていきましょう!
—
そもそも「切断型レコードセット」ってなに?
通常、データベースを操作するときは、サーバーやファイル(AccessならMDB/ACCDBファイル)に常に接続した状態でデータを読み書きしますよね。
しかし、考えてみてください。
- 何百件ものデータを画面上でユーザーがポチポチ編集している間、ずっとデータベースを占有し続けるのは、回線やサーバーにとって重い負担(パフォーマンスの低下)になります。
- ネットワークが不安定な環境だったら、途中で接続が切れてエラーになってしまいます。
そこで登場するのが「切断(Disconnected)」という発想です。
> 【イメージ図】
> 1. 接続(Connect): データベースから必要なデータを一気に取得する
> 2. 切断(Disconnect): その瞬間にデータベースとの接続をプツッと切り捨てる
> 3. 編集(Edit): ネットワークもサーバーも関係ない、自分の手元(PCのメモリ上)だけで自由にデータをイジる
> 4. 再接続(Reconnect): 編集が終わったら、再びデータベースにつないで、変更データを「まとめて一括送信」する
これが、プロの現場でよく使われる「切断型レコードセット」の正体です。ものすごく効率的で、スマートなやり方だと思いませんか?
—
なぜADOを使うの?(DAOとの違い)
Accessの標準であるDAO(Data Access Objects)でもデータ操作はできますが、この「接続を切り離してメモリ上で遊ばせる(独立させる)」という芸風において、真価を発揮するのがADO(ActiveX Data Objects)です。
ADOのRecordsetオブジェクトは、接続元(Connection)から独立してメモリ上に常駐する機能を持っています。これが、今回のテクニックのキモになります。
—
実践!切断型レコードセットを操るコード
百聞は一見に如かず。実際にコードを見てみましょう。
今回は、社内の「商品マスター」からデータをメモリ上に読み込み、接続を切った状態で価格を書き換え、最後にまとめてデータベースに反映させるシナリオです。
開発環境のVBE(Visual Basic Editor)を開き、標準モジュールに以下のコードを貼り付けてみてください。
Sub DisconnectedRecordsetSample()
‘ 宣言セクション
Dim cn As Object
Dim rs As Object
Dim connStr As String
‘ 1. 接続文字列の作成(現在のAccessファイル自身を対象にする場合)
connStr = “Provider=Microsoft.ACE.OLEDB.12.0;Data Source=” & CurrentDb.Name
‘ Connectionオブジェクトの生成
Set cn = CreateObject(“ADODB.Connection”)
cn.Open connStr
‘ 2. Recordsetオブジェクトの生成とデータ取得
Set rs = CreateObject(“ADODB.Recordset”)
‘ 【重要】ここがポイント!
‘ サーバーから切り離された「切断型(クライアントサイド)」として開く設定
rs.CursorLocation = 3 ‘ adUseClient
‘ データを取得(例:商品マスターから全件取得)
rs.Open “SELECT FROM M_商品”, cn, 3, 3 ‘ adOpenStatic, adLockOptimistic
‘ ==========================================
‘ 3. ★ここでデータベースとの接続を切断する!★
‘ ==========================================
Set rs.ActiveConnection = Nothing
‘ 4. データベースが閉じている(接続が切れている)ことを確認
‘ ここから先は、ファイルを閉じていようがネットワークが切れていようが関係ありません!
cn.Close
Set cn = Nothing
MsgBox “データベースから切断しました。これよりメモリ上で自由に編集します。”, vbInformation
‘ 5. メモリ上のレコードセットを自由気ままに編集
rs.MoveFirst
Do Until rs.EOF
‘ 例として、すべての商品の単価を10%アップさせる
rs.Fields(“単価”).Value = rs.Fields(“単価”).Value 1.1
rs.MoveNext
Loop
MsgBox “メモリ上の編集が完了しました。これからデータベースに一括反映します!”, vbInformation
‘ ==========================================
‘ 6. 再びデータベースに接続して、変更を同期する
‘ ==========================================
Set cn = CreateObject(“ADODB.Connection”)
cn.Open connStr
‘ アクティブ接続を再設定
Set rs.ActiveConnection = cn
‘ 変更内容をデータベースに一括書き戻し(アップデート)
rs.UpdateBatch
‘ 7. 後片付け
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
MsgBox “すべての処理が正常に完了しました!”, vbInformation
End Sub
—
コードの深掘りポイント(ここが分かれば怖くない!)
初心者がつまづきやすいポイントを、エンジニアの視点で優しく解説します。
① `rs.CursorLocation = 3` とは?
ADOには、サーバー側でデータを管理する方式(Serverサイド)と、手元のPCのメモリ上でデータを管理する方式(Clientサイド)があります。
切断型を作るには、「データをクライアント(手元)に丸ごと持ってくるよ」という宣言(`adUseClient` = 3)が絶対に必要になります。これが大前提です。
② `Set rs.ActiveConnection = Nothing` の魔法
これが今回のメインディッシュです。
レコードセットが持っている「どこにつながっているか」というプロパティ(`ActiveConnection`)に `Nothing`(空っぽ)を代入することで、「もうお前はどのデータベースとも繋がっていないよ、自由の身だ!」と解放してあげます。
これにより、データベース側のロックやコネクションを解放し、システム全体の負荷を劇的に下げることができます。
③ `rs.UpdateBatch` で一括同期
メモリ上でどれだけデータを書き換えようとも、接続を切っている間はデータベースの本体は1ミリも変わりません。
最後に再びConnectionを繋ぎ直し、`rs.ActiveConnection = cn` で「お帰り、またつながったよ」と教えてあげた後、`rs.UpdateBatch`を実行することで、メモリ上の変更がデータベースへ雪崩れ込むように一括反映されます。この一連の流れが美の極みです。
—
陥りやすいエラーと注意点
実務でこのテクニックを使うとき、以下の罠にハマることがあります。あらかじめ知っておきましょう。
- 主キー(プライマリキー)がないテーブルだとエラーになる
`UpdateBatch`を使うとき、データベース側とメモリ上のレコードを「どれとどれが同じデータか」を紐付ける必要があります。そのため、対象のテーブルには必ず主キー(一意制約)を設定しておいてください。主キーがないと、「どのデータを更新していいかわからないよ!」とADOに怒られてしまいます。
- 楽観的排他制御の意識
切断している間に、もし他のユーザーが同じデータを書き換えていたら……? 実際のシステムでは、同時更新のバッティング(競合)が起きる可能性があります。複数人でバリバリ同時編集するようなカオスな環境では、エラーハンドリング(`On Error`)をしっかり組む心の余裕を持ちましょう。
—
まとめ
いかがでしたか?
「ADOの切断型レコードセット」は、一見すると少しコードが長く見えますが、やっている本質はとてもシンプルです。
1. データを手元に持ってくる
2. つながりを断つ
3. 手元で自由に料理する
4. 再びつながって、ドンとまとめて書き戻す
ここをクリアできれば、あなたはもう「ただAccessの画面をポチポチ作る人」ではなく、「背後のリソースやパフォーマンスまで計算できる優れたシステムエンジニア」の仲間入りです。
ぜひ自分の開発環境でも試して、この「接続を断つ快感」を味わってみてください。あなたのAccess VBAライフが、より一層深まることを応援しています!
