【入門編】DAOのFindFirstメソッドとADOのFindメソッド:検索速度と柔軟性の比較 – Access VBA解析バイブル

スポンサーリンク

こんにちは!Access VBAの世界へようこそ。
マクロの記録から一歩踏み出し、「自分で自在にシステムを操りたい」と願うあなたへ。今日はいよいよ、プログラミングの醍醐味である「データの検索」について、少し踏み込んだ話をしましょう。

大量のデータの中から、お目当ての1行を見つけ出す。
Access VBAには、この検索を行うための代表的なメソッドが2つあります。それが、DAO(ダオ)の`FindFirst`と、ADO(エイディオ)の`Find`です。

「どっちを使っても一緒でしょ?」なんて思っていませんか?
実はこの2つ、中身のエンジンも、得意なシチュエーションも全く違います。ここをクリアすれば、あなたの書くコードのスピードと質は劇的に変わりますよ。

それでは、エンジニアの先輩として、優しく、そして本質的なところまでしっかりと解説していきますね。

—

1. DAOとADO、そして「検索」の基本概念

まずは、土台となる「DAO」と「ADO」の違いを、ざっくりとイメージ図で捉えてみましょう。

  • DAO(Data Access Objects)
  • イメージ: Access(Jet/ACEエンジン)専用に作られた、生粋のエリート。
  • 特徴: Accessのファイルと相性抜群。ローカルのテーブルをいじらせたら右に出る者はいません。
  • ADO(ActiveX Data Objects)
  • イメージ: SQL ServerやOracleなど、外の世界とも渡り合えるグローバルな外交官。
  • 特徴: どんなデータベースにも接続できる万能選手ですが、Accessのローカル操作では少しオーバースペックになることも。

この2つのエンジンでレコードを探すとき、DAOは「`FindFirst`」を使い、ADOは「`Find`」を使います。名前は似ていますが、その裏側の動きは全く異なります。

—

2. 検索速度と柔軟性のガチンコ比較

「どっちが速いの?」という疑問に、現場のアーキテクチャの視点から答えましょう。結論から言うと、Accessのローカルテーブルを相手にする限り、速度・手軽さともにDAO(`FindFirst`)の圧勝です。

特徴の比較表

| 項目 | DAO: `FindFirst` | ADO: `Find` |
| :— | :— | :— |
| 得意な場所 | Accessローカルテーブル | サーバーDB、レコードセット内 |
| 検索スピード (ローカル) | 高速(インデックスが効く) | やや遅い(全件走査的) |
| 条件の書き方 | SQLの `WHERE` 句に似ている | 独自の条件式(少し癖がある) |
| 該当なしの挙動 | `NoMatch = True` になる | EOF(ファイルの最後)に達する |

なぜDAOのほうが速いのか?
それは、DAOがAccessのデータベースエンジン(ACE)と直結しており、テーブルに設定された「インデックス(索引)」をダイレクトに利用できるからです。分厚い辞書の索引パッと開くようなイメージですね。

一方、ADOの`Find`は、メモリ上に読み込んだレコードセットに対してフィルターをかけるような動きをします。そのため、純粋なAccessのローカル検索では、DAOに軍配が上がることが多いのです。

—

3. 実践!コードで見る書き方と使い方

百聞は一見にしかず。実際にそれぞれのコードを見てみましょう。
ここでは、「社員マスター」テーブルから、「社員IDが ‘E00123’ の人を探す」というシチュエーションを考えてみます。

パターンA:DAOの `FindFirst` を使う場合(推奨)

AccessVBAの標準装備であるDAOを使った、最も王道でスマートな書き方です。

Sub SearchByDAO()
Dim db As DAO.Database
Dim rs As DAO.Recordset

‘ 現在のデータベースを参照
Set db = CurrentDb

‘ テーブルを開く(テーブル名:T_社員マスター)
Set rs = db.OpenRecordset(“T_社員マスター”, dbOpenDynaset)

‘ 検索条件を指定して実行(例: 社員IDが ‘E00123’ のレコード)
rs.FindFirst “社員ID = ‘E00123′”

‘ 見つかったかどうかを判定
If rs.NoMatch Then
MsgBox “お探しのデータは見つかりませんでした。”, vbExclamation
Else
‘ 見つかった場合の処理(例:氏名を表示)
MsgBox “見つかりました! 氏名: ” & rs.Fields(“氏名”).Value, vbInformation
End If

‘ 【重要】オブジェクトは必ず解放する(メモリリーク防止)
rs.Close
Set rs = Nothing
Set db = Nothing

Set db = Nothing
End Sub

ここがポイント!
`rs.NoMatch` という専用の看板が用意されているのがDAOの優しいところ。「あ、見つからなかったんだな」と直感的にコードが書けます。

—

パターンB:ADOの `Find` を使う場合

次に、少し高度なADOを使った書き方です。SQL Server等に接続する場合や、あえてADOのレコードセットを使いたい時はこちらになります。

Sub SearchByADO()
Dim conn As Object
Dim rs As Object

‘ 接続オブジェクトとレコードセットオブジェクトの生成
Set conn = CurrentProject.Connection
Set rs = CreateObject(“ADODB.Recordset”)

‘ レコードセットを開く
rs.Open “T_社員マスター”, conn, 1, 3 ‘ adOpenKeyset, adLockOptimistic相当

‘ ADOのFindメソッドで検索
‘ ※ADOのFindは、条件に合致する最初の行にカーソルを移動します
rs.Find “社員ID = ‘E00123′”

‘ 見つかったかどうかの判定(EOFに達していなければヒット)
If rs.EOF Then
MsgBox “お探しのデータは見つかりませんでした。”, vbExclamation
Else
MsgBox “見つかりました! 氏名: ” & rs.Fields(“氏名”).Value, vbInformation
End If

‘ 後片付け
rs.Close
Set rs = Nothing
Set conn = Nothing
End Sub

ここがポイント!
ADOの`Find`は、見つからないとレコードセットの末尾(`EOF`)にポインタが移動します。「`If rs.EOF Then`」で判定するのがお作法です。少し通な書き方ですね。

—

4. 初学者が陥りやすい罠とエラー回避の極意

現場でコードを書いていると、必ずと言っていいほどエラーにぶぶつかります。よくある失敗パターンをあらかじめ知っておきましょう。

罠1:文字列のシングルクォーテーション(’)忘れ

条件式の中に変数を組み込むとき、文字列型(Text型)のデータにはシングルクォーテーションが必要です。

  • × 駄目な例: `rs.FindFirst “社員ID = ” & txtID` (値が数値ならOKですが、文字だとエラーになります)
  • 〇 正しい例: `rs.FindFirst “社員ID = ‘” & txtID & “‘” `

この「ダブルとシングルの迷宮」にハマる初心者は後を絶ちません。迷ったら、一度変数に条件の文字列を代入して、`Debug.Print` でイミディエイトウインドウに出力して確認する癖をつけましょう。

罠2:オブジェクトの解放忘れ(メモリリーク)

コードの最後にある `rs.Close` や `Set rs = Nothing`。
「動くからいいや」と省略していませんか? これをサボると、見えないところでメモリがどんどん消費され、Accessがフリーズする原因になります。プログラミングの基本は「借りたものは返す」です。

—

まとめ:結局どちらを使うべき?

最後に、シニアエンジニアからの結論です。

  • 通常のAccessファイル(ACCDB)内でデータを検索するなら

⇒ 迷わず DAO (`FindFirst`) を使ってください。 コードがシンプルで、処理も速く、Accessの恩恵を最大限に受けられます。

  • 将来的にSQL Serverなどの外部DBへ移行する予定がある、またはすでにADOを使っているなら

⇒ ADO (`Find`) の作法をマスターしておきましょう。

ここをクリアすれば、あなたはもう「マクロの記録」を卒業した立派なAccess VBAエンジニアです。データ検索のスピードと確実性を手に入れて、サクサク動くスマートなシステムを作っていきましょう!

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