【入門編】DAOのRecordsetをExcelへ一括出力:DoCmd.TransferSpreadsheetより柔軟な制御 – Access VBA解析バイブル

スポンサーリンク
スポンサーリンク

「TransferSpreadsheet」の限界を超えて。DAO RecordsetでExcelへ「魂」を込めた出力を行う技術

こんにちは。よくここまでAccess VBAの学習を積み重ねてきましたね。

「マクロの記録」から一歩踏み出し、自分でコードを書き始めたあなたなら、一度はこんな壁にぶつかったことがあるはずです。

「`DoCmd.TransferSpreadsheet` は便利だけど、出力したExcelの見た目が素っ気なすぎる……」
「出力の途中で、値によって色を変えたり、特定の条件の時だけ行を飛ばしたりしたい……」

そう、標準機能の「一括出力」は、いわば「全自動の大量輸送トラック」です。速いけれど、荷物の詰め方(書式)や、途中で荷物を整理する(制御)といった繊細なことはできません。

今日は、そんな「自動化の限界」を突破するための、伝説的なエンジニアが愛用する「DAO Recordset × Excel Object Model」による、自由自在なデータ転送の極意を伝授します。ここをクリアすれば、あなたのAccess VBAは「単なる道具」から「プロフェッショナルなシステム」へと進化しますよ。

1. なぜ「DAO」なのか? ADOとの決定的な違い

まず、ここで一度立ち止まって、アーキテクチャの基礎を確認しましょう。データを扱う技術には、大きく分けてDAOとADOの2種類があります。

特徴 DAO (Data Access Objects) ADO (ActiveX Data Objects)
得意領域 Access内部のデータ操作(最強) 外部サーバー(SQL Server等)への接続
速度 Accessエンジンに最適化されており高速 ネットワーク越しでの汎用性が高い
設計思想 Accessの構造を深く理解している どんなデータベースとも会話できる

今回のテーマは「Access内のデータをExcelへ」です。この場合、DAOを使うのが正解です。
DAOはAccessの心臓部(Jet/ACEエンジン)と直結しているため、ローカルテーブルの操作において、最も軽量で、かつ「Accessらしい」挙動をします。

「ADOの方が新しそうだから」という理由でADOを選ぶのは、近所のコンビニに買い物に行くのに、わざわざ大型トラックをチャーターするようなもの。無駄なコスト(メモリ消費やオーバーヘッド)がかかってしまうのです。

2. 自由を手に入れるための「黄金の設計図」

`DoCmd.TransferSpreadsheet` が「テーブルを丸ごとコピーする」のに対し、私たちがこれから実装するのは「一軒一軒、丁寧に荷物を運び込む」手法です。

イメージ図は以下の通りです:

1. DAO Recordsetを生成: 「どのデータを、どんな条件で持ってくるか」を定義。
2. Excel Applicationを起動: 「真っ白なキャンバス」を用意。
3. ループ(反復処理)開始: Recordsetのレコードを一行ずつ読み込む。
4. セルへの書き込み + 制御: 「値が100以上なら赤字にする」といった判断をここで実行。
5. 後片付け: 開いたExcelやRecordsetを確実に閉じる(※これが最重要!)。

3. 実践:書式を操る「極限の出力コード」

それでは、実際に使えるコードを見ていきましょう。
このコードは、単にデータを出すだけでなく、「値によってセルの色を変える」という柔軟な制御を組み込んでいます。

Option Compare Database
Option Explicit

''' <summary>
''' DAO Recordsetの内容をExcelへ、書式を制御しながら出力する
''' </summary>
Public Sub ExportDataWithFormat()
    ' --- 1. オブジェクト変数の宣言 ---
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim xlApp As Excel.Application
    Dim xlWb As Excel.Workbook
    Dim xlWs As Excel.Worksheet
    Dim strSql As String
    Dim i As Long, j As Integer
    
    ' エラーハンドリングの設定
    On Error GoTo ErrorHandler

    ' --- 2. データの準備 (DAO) ---
    Set db = CurrentDb
    strSql = "SELECT 社員ID, 社員名, 売上金額 FROM T_Sales ORDER BY 売上金額 DESC;"
    Set rs = db.OpenRecordset(strSql, dbOpenSnapshot) ' 読み取り専用で高速化

    ' データが空の場合の処理
    If rs.EOF Then
        MsgBox "出力するデータがありません。", vbExclamation
        GoTo CleanUp
    End If

    ' --- 3. Excelの起動 ---
    ' Excelをバックグラウンドで起動
    Set xlApp = New Excel.Application
    Set xlWb = xlApp.Workbooks.Add
    Set xlWs = xlWb.Worksheets(1)
    
    ' Excelを可視化(デバッグ中や、最後にユーザーに見せる場合に便利)
    xlApp.Visible = True

    ' --- 4. ヘッダーの作成 ---
    For j = 0 To rs.Fields.Count - 1
        xlWs.Cells(1, j + 1).Value = rs.Fields(j).Name
        xlWs.Cells(1, j + 1).Font.Bold = True ' ヘッダーを太字に
        xlWs.Cells(1, j + 1).Interior.Color = RGB(220, 220, 220) ' 背景色をグレーに
    Next j

    ' --- 5. データの書き込みと「条件付き書式」の制御 ---
    i = 2 ' 書き出し開始行(ヘッダーの次)
    
    Do Until rs.EOF
        ' 列ごとにループしてセルへ書き込み
        For j = 0 To rs.Fields.Count - 1
            xlWs.Cells(i, j + 1).Value = rs.Fields(j).Value
            
            ' 【ここが柔軟性のキモ!】
            ' 例:売上金額(3番目のフィールド)が500,000を超えたら赤字にする
            If j = 2 Then ' 0から数えるので、3番目はインデックス2
                If rs.Fields(j).Value >= 500000 Then
                    xlWs.Cells(i, j + 1).Font.Color = vbRed
                    xlWs.Cells(i, j + 1).Font.Bold = True
                End If
            End If
        Next j
        
        rs.MoveNext ' 次のレコードへ
        i = i + 1
    Loop

    ' 列幅の自動調整
    xlWs.Columns.AutoFit

    MsgBox "Excelへの出力が完了しました!", vbInformation

' --- 6. 後片付け(クリーンアップ) ---
CleanUp:
    On Error Resume Next
    ' オブジェクトを解放(メモリリークを防ぐための鉄則)
    If Not rs Is Nothing Then rs.Close: Set rs = Nothing
    If Not db Is Nothing Then Set db = Nothing
    ' Excelを閉じる(必要に応じて xlWb.SaveAs などを行う)
    ' Set xlWb = Nothing
    ' Set xlApp = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました。" & vbCrLf & _
           "番号: " & Err.Number & vbCrLf & _
           "内容: " & Err.Description, vbCritical
    Resume CleanUp
End Sub

4. プロが教える「陥りやすい罠」と回避策

このコードを使いこなすために、絶対に覚えておいてほしい「設計上の注意点」が2つあります。

① オブジェクトのライフサイクル(後片付けの重要性)

VBAの世界では、`Set obj = Nothing` と書くことで、使用したメモリをシステムに返却します。
特にExcelのような外部アプリケーションを操作する場合、「エラーが起きても、必ず `CleanUp` に飛んでオブジェクトを閉じる」という構造にしないと、Excelのプロセスだけが裏で大量に残ってしまう「ゾンビプロセス」が発生します。これはPCの動作を重くする元凶です。

② パフォーマンスの壁(速度の出し方)

上記のコードは「1セルずつ」書き込んでいます。これは非常に柔軟ですが、データが数万件ある場合は非常に遅くなります。

もし、「書式はいらないから、とにかく高速に大量のデータを移したい」という場合は、以下のステップを検討してください:
1. Recordsetの内容を一度 「Variant型の配列」 に格納する。
2. Excelの範囲に対して、配列を一括で流し込む(`Range(“A2:C10000”).Value = myVariantArray`)。

「柔軟性(1セルずつ)」と「速度(一括)」の使い分け。これこそが、アーキテクトの判断基準です。

まとめ:ここをクリアすれば、もう初心者卒業です

`DoCmd.TransferSpreadsheet` は、決まった形のデータを素早く出すための「便利な道具」です。
しかし、今回学んだ 「DAO Recordsetを回して、Excel Object Modelで制御する」 手法は、ユーザーの要望に応えるための「強力な武器」になります。

  • DAOはAccess内部操作の王様。
  • Recordsetのループの中で、条件分岐による書式制御を行う。
  • エラーが起きても必ずオブジェクトを解放する(CleanUp)。

この3点を意識するだけで、あなたの作るツールは劇的にプロフェッショナルなものに変わります。

さあ、恐れずにコードを書いてみてください。エラーが出たときは、それはあなたが成長するための「ヒント」です。応援していますよ!

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