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

スポンサーリンク

【Access VBA極致】DoCmd.TransferSpreadsheetを捨てろ。DAOとExcel Rangeの直結による「爆速」エクスポート術

Access開発の現場で、一度は通る道がある。
「クエリの結果をExcelに書き出す」というありふれた要件だ。

多くの開発者が迷わず `DoCmd.TransferSpreadsheet` を叩く。だが、もし君が「世界最高峰の業務自動化」を目指しているのなら、その選択は今すぐ捨てるべきだ。

なぜか? `DoCmd.TransferSpreadsheet` は、ファイルI/Oのオーバーヘッドが大きく、フォーマットの柔軟性も皆無だからだ。数万件のデータを吐き出すたびに、PCがフリーズしたような挙動を見せるのは、君のコードがボトルネックになっている証拠である。

今日は、DAOの `QueryDef` をハブに、Excelの `Range` オブジェクトへメモリ経由で直接データを叩き込む、プロフェッショナルな実装手法を伝授する。

—

なぜDAO経由のRecordset操作が「最強」なのか

理由はシンプルだ。「中間ファイル」を生成しないからだ。

1. メモリ内展開: `QueryDef` でコンパイルされたSQLを `Recordset` として開く。
2. 一括転送: `Range.CopyFromRecordset` を用いることで、セル一つひとつに書き込むような低速なループを回避する。
3. ライフサイクル管理: `QueryDef` を動的に生成して即座に破棄することで、データベースの肥大化(IDの無駄な消費やロック)を防ぐ。

—

実践:プロダクションレベルの高速エクスポートコード

以下のコードは、保守性と堅牢性を担保したテンプレートだ。そのまま君のライブラリに組み込んでほしい。

‘ —————————————————————————
‘ 概要: QueryDefで作成したクエリをExcelへ爆速エクスポートする
‘ 備考: DoCmd.TransferSpreadsheetは使用せず、メモリベースで転送する
‘ —————————————————————————
Public Sub ExportQueryToExcel(ByVal strQueryName As String, ByVal strFilePath As String)
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim xlApp As Object ‘ バインディングの柔軟性を考慮
Dim xlWb As Object
Dim xlWs As Object

Set db = CurrentDb

‘ 1. QueryDefの存在確認とRecordsetの取得
On Error Resume Next
Set qdf = db.QueryDefs(strQueryName)
If Err.Number <> 0 Then
MsgBox “指定されたクエリが見つかりません。”, vbCritical
Exit Sub
End If
On Error GoTo 0

Set rs = qdf.OpenRecordset(dbOpenSnapshot) ‘ スナップショットで読み取り専用かつ高速に

If rs.EOF Then
MsgBox “出力対象のデータが存在しません。”, vbExclamation
GoTo Cleanup
End If

‘ 2. Excelアプリケーションの起動
Set xlApp = CreateObject(“Excel.Application”)
Set xlWb = xlApp.Workbooks.Add
Set xlWs = xlWb.Sheets(1)

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

‘ 4. データの一括転送 (ここが最速のポイント)
xlWs.Range(“A2”).CopyFromRecordset rs

‘ 5. 保存とクリーンアップ
xlWb.SaveAs strFilePath
xlWb.Close SaveChanges:=False
xlApp.Quit

Cleanup:
If Not rs Is Nothing Then rs.Close: Set rs = Nothing
If Not qdf Is Nothing Then Set qdf = Nothing
Set xlWs = Nothing: Set xlWb = Nothing: Set xlApp = Nothing
Set db = Nothing
End Sub

—

匠のこだわり:設計上の注意点

1. `dbOpenSnapshot` の呪文

DAOでクエリを開く際、デフォルトの `dbOpenDynaset` を使ってはならない。編集不要なエクスポート処理において、レコードロックのオーバーヘッドを付与するのは愚行だ。必ず `dbOpenSnapshot` を指定せよ。

2. `CopyFromRecordset` の制限を理解する

このメソッドは非常に高速だが、「OLEオブジェクト型」や「ハイパーリンク型」のフィールドでエラーを吐くことがある。もしこれらのデータが含まれる場合は、事前にクエリ側で `Nz()` や `CStr()` を使い、型を文字列や数値にキャストしておくのがプロの作法だ。

3. 疎結合(Late Binding)の採用

コード内で `Object` 型を使用しているのは、Excelのバージョン差異による参照設定のトラブルを回避するためだ。現場に配布するツールであれば、環境依存を極限まで排除するのがリーダーの務めである。

—

まとめ:自動化の先にあるもの

「動けばいい」というレベルのコードは、いずれ技術的負債となって君の首を絞める。`QueryDef` を賢く使い、メモリとデータフローを制御する。この視点を持つだけで、君が作る業務ツールは「重い・遅い・止まる」という汚名を返上できるはずだ。

次は、このコードに「パラメータークエリを動的に構築する仕組み」を組み合わせて、ユーザーの入力を安全にSQLへ反映させる方法を論じよう。

君のコードが、現場の空気を変える武器になることを期待している。

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