Access VBAの深淵へようこそ:DAOのFindFirstとADOのFilter、どちらを選ぶべきか?
こんにちは。今日までマクロの記録や、断片的なコードの書き写しで頑張ってきたあなた。その努力は素晴らしいものです。しかし、もしあなたが「プログラムがなぜか遅い」「もっとスマートに書きたい」と感じ始めているなら、それはあなたが「エンジニア」への入り口に立っている証拠です。
今日は、Access VBAにおける二大勢力、DAO(Data Access Objects)とADO(ActiveX Data Objects)のアーキテクチャの違い、そして検索処理における「決定的な使い分け」についてお話ししましょう。
単なる「書き方の違い」ではありません。これは「データの動き(ライフサイクル)」を支配するための知恵です。ここをクリアすれば、あなたのAccessアプリケーションは別次元のスピードと安定性を手に入れることができますよ。
1. そもそも、DAOとADOは何が違うのか?
「どちらもデータを扱うものじゃないか」と思うかもしれません。しかし、その立ち位置は全く異なります。
DAO:Accessエンジンの「直通電話」
DAOは、Accessの心臓部である「Jet/ACEエンジン」のために設計された、いわば純正の通信手段です。Accessのテーブル構造やインデックス(索引)を最も深く理解しており、エンジンに対して「このインデックスを使って、この値を直接見つけて!」と、最短距離で命令を伝えることができます。
ADO:外部世界への「万能な翻訳機」
一方、ADOは、SQL ServerやOracleといった外部のデータベースとも対話できるように作られた、汎用的な通信手段です。非常に洗練されたインターフェースを持っていますが、Access内部で使う場合、一度「翻訳」の工程が入るため、DAOに比べるとわずかにオーバーヘッド(余計な負荷)が生じることがあります。
2. 検索メソッドの正体:FindFirst vs Filter
さて、本題の検索メソッドについて掘り下げましょう。ここがパフォーマンスの分岐点です。
DAOの `FindFirst`:インデックスを駆使する「一撃の狙撃手」
`FindFirst`は、レコードセットの中を先頭から順番に、あるいはインデックス(索引)を使って、条件に一致する最初の1件を探し出すメソッドです。
- 動作の仕組み: もし検索対象のフィールドに「インデックス」が貼られていれば、エンジンは全データを走査することなく、インデックスを辿って一瞬で目的の場所にジャンプします。
- 得意なこと: 「特定のIDを持つレコードを1件だけ見つけたい」という、ピンポイントな検索。
ADOの `Filter`:条件で切り取る「魔法のフィルター」
`Filter`プロパティは、レコードセット全体の中から、条件に一致するものだけを抽出した「新しいサブセット(部分集合)」をメモリ上に作り出す操作です。
- 動作の仕組み: 条件に合うレコードをすべて抽出し、それだけが見える「窓」を新しく作り直すイメージです。
- 得意なこと: 「『売上高が10万以上』のレコードだけを一覧表示したい」という、条件に合うグループの抽出。
3. 実践コード:使い分けの極意
では、実際にどのようにコードを書くべきか、比較してみましょう。
【パターンA】DAOで高速に1件を特定する
大量のデータ(例:10万件の顧客マスタ)から、特定の社員番号を探す場合は、迷わずDAOの`FindFirst`を選んでください。
Sub SearchWithDAO()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim targetID As String
targetID = "E12345" ' 探したいID
Set db = CurrentDb
' テーブルを開く(インデックスが効くようにする)
Set rs = db.OpenRecordset("T_Employee", dbOpenDynaset)
' 【ここがポイント】FindFirstを使用
' インデックスが貼られていれば、爆速で完了します
rs.FindFirst "EmployeeID = '" & targetID & "'"
If Not rs.NoMatch Then
Debug.Print "発見! 氏名: " & rs![EmployeeName]
Else
Debug.Print "見つかりませんでした。"
End If
' 後始末はエンジニアのたしなみ
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
【パターンB】ADOで条件に合うリストを抽出する
「特定の部署に所属するメンバー全員」を抽出して、何らかの処理を行いたい場合は、ADOの`Filter`が直感的で使いやすい場面があります。
Sub FilterWithADO()
Dim cn As ADO.Connection
Dim rs As ADO.Recordset
Dim filterStr As String
filterStr = "Department = 'Sales'" ' 部署がSalesの人
Set cn = CurrentProject.Connection
Set rs = New ADO.Recordset
' レコードセットを開く
rs.Open "T_Employee", cn, adOpenStatic, adLockReadOnly
' 【ここがポイント】Filterを使用して、条件に合うものだけに絞り込む
' 抽出された「新しい集合」に対して操作を行うイメージです
rs.Filter = filterStr
If rs.EOF Then
Debug.Print "該当者なし"
Else
Do Until rs.EOF
Debug.Print "氏名: " & rs!EmployeeName
rs.MoveNext
Loop
End If
' 後始末
rs.Close
Set rs = Nothing
Set cn = Nothing
End Sub
4. 結論:どちらを選ぶべきか?(判断基準チャート)
迷ったときは、以下の基準を思い出してください。
| 状況 | 推奨メソッド | 理由 |
|---|---|---|
| 大量のデータから1件だけ探したい | DAO `FindFirst` | インデックスを活用でき、メモリ消費も最小限で済むため。 |
| 条件に合う「グループ」を扱いたい | ADO `Filter` | 抽出後の集合に対して、そのままループ処理などが容易に行えるため。 |
| Access内のローカルテーブルを扱う | DAO | エンジン直結の圧倒的なパフォーマンスを享受できるため。 |
| SQL Serverなどの外部DBを扱う | ADO | 外部接続の標準的な作法であり、汎用性が高いため。 |
⚠️ 初学者が陥りやすい「落とし穴」
「ループの中で `Filter` を何度も呼び出さないこと」
これが最も重要なアドバイスです。
例えば、「1,000件のデータに対して、1件ごとに `Filter` をかけて新しいサブセットを作る」という処理を書いてしまうと、そのたびにメモリ上に新しい集合が構築され、動作は劇的に重くなります。
このような場合は、「最初からSQL(SELECT文)で条件を絞り込んでからレコードセットを開く」のが、プロのアーキテクトのやり方です。
最後に
DAOとADOの違いを理解することは、単に「動くコード」を書く段階から、「効率的なシステム」を設計する段階へステップアップすることを意味します。
「なぜこのメソッドを使うのか?」
その理由を、データの動き(インデックスなのか、新しい集合なのか)の観点から説明できるようになれば、あなたはもう立派なエンジニアです。
一歩ずつ、確実に。コードの裏側にある「理(ことわり)」を楽しんでくださいね。応援していますよ!
