【入門編】DAO.QueryDefで作成したクエリをExcelへ高速エクスポートする手法 – Access VBA解析バイブル

スポンサーリンク

Access VBAの極致:DoCmdに頼らない「爆速」Excelエクスポート術

こんにちは。現場で泥臭い自動化と格闘し、システムを最適化し続けているエンジニアです。

Accessを使っていて「`DoCmd.TransferSpreadsheet` でExcel出力したら、なぜか遅いし細かな調整が効かない……」と頭を抱えたことはありませんか?実は、それ、Accessの「本来の力」を使いこなせていないだけかもしれません。

今回は、DAOの`QueryDef`と`Recordset`を組み合わせ、メモリ上でデータを捌き、Excelへ高速に流し込む「プロの定石」を伝授します。これさえ習得すれば、Access VBAの景色がガラリと変わりますよ。

—

なぜ DoCmd は「遅い」のか?

`DoCmd.TransferSpreadsheet` は非常に便利ですが、内部でファイルを開いたり閉じたり、AccessとExcelの間で過剰な通信が発生したりと、オーバーヘッド(無駄な待ち時間)が非常に大きいのです。

一方、今回紹介する手法は、「DAOでデータをメモリに吸い上げ、ExcelのCOMオブジェクト経由で一気にセルへ流し込む」というアプローチです。これを覚えると、数万件のデータ出力も劇的に速くなります。

—

実践:QueryDef と Recordset を使った高速エクスポート

まずは、以下のコードを見てください。これが「現場の標準」です。

Public Sub ExportQueryToExcel_Fast()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim xlApp As Object
Dim xlBook As Object
Dim xlSheet As Object

Set db = CurrentDb
‘ QueryDefを取得(パラメータクエリにも対応可能)
Set qdf = db.QueryDefs(“qry_売上データ”)

‘ ここでパラメータを動的にセットすることも可能
‘ qdf.Parameters(“[Forms]![frm_Menu]![txtStartDate]”) = “2023/04/01”

Set rs = qdf.OpenRecordset(dbOpenSnapshot)

‘ レコードが存在しない場合のガード
If rs.EOF Then
MsgBox “対象データがありません。”
GoTo Cleanup
End If

‘ Excelを起動
Set xlApp = CreateObject(“Excel.Application”)
Set xlBook = xlApp.Workbooks.Add
Set xlSheet = xlBook.Sheets(1)

‘ ヘッダーの書き込み
Dim i As Integer
For i = 0 To rs.Fields.Count – 1
xlSheet.Cells(1, i + 1).Value = rs.Fields(i).Name
Next i

‘ データの一括転送(RangeへのCopyFromRecordsetが最強の秘訣)
‘ 1セルずつ書き込むのは素人。一気にメモリから流し込むのがプロ。
xlSheet.Range(“A2”).CopyFromRecordset rs

xlApp.Visible = True

Cleanup:
‘ オブジェクトの解放(メモリリークを防ぐ鉄則)
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
Set qdf = Nothing
Set db = Nothing
Set xlSheet = Nothing: Set xlBook = Nothing: Set xlApp = Nothing
End Sub

—

ここがプロのポイント!

1. `CopyFromRecordset` を使う

このメソッドこそが高速化の核心です。1セルずつ `Cells(i, j).Value = …` とループで書き込んでいると、処理時間はデータ量に比例して爆発的に増えます。`CopyFromRecordset` は、RecordsetのデータをメモリブロックとしてExcelのセル範囲に一気にコピーするため、体感速度が桁違いです。

2. `dbOpenSnapshot` の活用

`OpenRecordset` を開く際、デフォルトではなく `dbOpenSnapshot` を指定してください。これは「読み取り専用の静的なデータ」としてメモリに保持するため、編集の必要がないエクスポート処理において、最も軽量で高速なモードです。

3. オブジェクトの「行儀よい」解放

初心者の方で意外と忘れがちなのが、`Set … = Nothing` による解放です。Access VBAはガベージコレクションが強力ではありません。特にExcelのインスタンス(`xlApp`)を放置すると、タスクマネージャーにExcelが残る「ゴーストプロセス」が発生し、システムを徐々に重くします。終了処理は必ず書きましょう。

—

よくあるトラブルと解決策

  • 「データが多すぎてExcelの行数制限を超える」
  • 解決策:`rs.GetRows` を使い、Excelの最大行数(1,048,576行)ごとにシートを分割するロジックを組むのが正攻法です。
  • 「型変換エラーが出る」
  • 解決策:`QueryDef` であらかじめ書式を整えておくか、Access側で `Format()` や `CStr()` を使い、Excelが解釈しやすい形式(特に日付や数値)にキャストしてから投げましょう。

—

最後に:自動化の先にあるもの

この手法をマスターすれば、Accessは単なる「データベース」ではなく、「高度なデータ処理エンジン」に変貌します。

「動かないから何となくボタンを押す」段階から、「データがどうメモリを流れ、どうExcelに焼き付けられるか」をイメージできる段階へ。この一段階上の視点を持つだけで、あなたの書くコードの質は劇的に向上します。

もしコードが動かない、あるいはもっと複雑な条件(条件ごとのシート分割など)を実装したい場合は、ぜひ教えてください。次は「さらに一歩進んだアーキテクチャ」についてお話ししましょう。

あなたの自動化ライフが、より快適で創造的なものになりますように!

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