図1●アンケート結果(Accessのデータベース)を集計するExcelマクロを実行し,グ
図1●アンケート結果(Accessのデータベース)を集計するExcelマクロを実行し,グ
[画像のクリックで拡大表示]
図2●Accessでクエリーを作成している様子
図2●Accessでクエリーを作成している様子
[画像のクリックで拡大表示]
リスト1●Accessデータベースからデータを取り込むマクロ
リスト1●Accessデータベースからデータを取り込むマクロ
[画像のクリックで拡大表示]

 梅は咲いたか桜はまだかいな♪ 春ですねぇ。え?お前の頭の中は一年中春だろうって。そうです。笑いは健康の源,最も安上がりな健康法です。おや?そこの暗い顔の青年,何か悩みでも。

今月の相談

「アンケート集計を任されることになったのですが,もらったデータがAccessデータベース・ファイルでした(泣)。Excelのマクロでどうにかならないでしょうか? “任せてください”と言っちゃたので…」

 はっは~ん,Excelには滅法強いが,Accessはからっきし。よくいるよね,こういう人。さてさて,どうしましょうかねぇ。ExcelからDB(データベース)にアプローチする手段はいくつかありますが,「Excelのマクロでどうにか」ということですから,次のようにしましょう。

  1. Accessでクエリーを作成
  2. ExcelのマクロにAccessをバインド
  3. Excelのマクロでクエリーを実行
  4. クエリーの実行で抽出したレコードをExcelのワークシートに転記
  5. Excelの計算式でデータをカウントしてグラフ化(グラフ作成は手作業)

 これで,最終的な仕上がりは図1[拡大表示]のような感じになります。まったくAccessに触れる必要のないフルオートのマクロを作ることも可能ですが,ちょっと長くなりますので,今回は最低限のAccess操作はやってもらうことにしましょう。

似て非なるAccessオブジェクト

 さっそくDBファイル(アンケート.mdb)を開いて,Accessでクエリーを作成しましょう。対象となるテーブル(5Question)は一つしかありません。Accessの「デザインビューでクエリを作成する」をクリックして,テーブルを追加し,性別と年齢のフィールドに抽出条件を指定します(図2[拡大表示])。こうして性別,年齢別のデータを抽出するクエリーをいくつか作ります。

 次にExcelマクロを作成しますが,一つ注意してほしいことがあります。Excelのマクロで集計するわけですが,AccessのオブジェクトはやはりAccess VBAのメソッドやプロパティで操作しなければなりません。Accessのオブジェクト,特にテーブルはExcelと同じように表形式ですから,どうしてもExcelのシートと同じメソッドやプロパティで操作できるような感覚を覚えます。しかし,実際にはオブジェクトの構造は違うし,用意されているメソッドやプロパティも違います。似た名前なのに仕様が違うのでちょっとイライラするかもしれませんが,慣れてしまえば大丈夫です。

バインドすれば自由自在

 コードを解説しましょう(リスト1[拡大表示])。(1)でAccessをバインドします。今回は,事前に「参照設定」ダイアログで,Accessライブラリに参照設定をするアーリー・バインディングを使いましょう。これにより,Newキーワードでオブジェクト型の変数を宣言すると同時に,インスタンスが作成されます。

リスト1●Accessデータベースからデータを取り込むマクロ

Sub DataFromDB()
    Dim AccessApp As New Access.Application
    ~ 略(その他の変数の宣言) ~

    myQueryName = Array( _
        "Osu20", "Osu30", "Osu40", "Osu50", "Osu60", _
        "Mesu20", "Mesu30", "Mesu40", "Mesu50", "Mesu60")

    myDBName = "アンケート.mdb"

    With AccessApp
        .OpenCurrentDatabase _
            ThisWorkbook.Path & "\" & myDBName
        For i = 1 To 10
            .DoCmd.OpenQuery myQueryName(i - 1), acViewNormal
            Set CQRecodeSset = _
                CurrentDb.QueryDefs(myQueryName(i - 1)). _
                OpenRecordset
            With CQRecodeSset
                myStartRow = 4
                myStartColumn = 1
                k = 0
                Do While Not .EOF
                    For j = 1 To 6
                        Worksheets(myQueryName(i - 1)) _
                            .Cells(myStartRow + k, _
                            myStartColumn + j - 1).Value _
                            = .Fields(j).Value
                    Next j
                    .MoveNext
                    k = k + 1
                Loop
            End With

            .DoCmd.Close acQuery, myQueryName(i - 1)
            myRow = Worksheets(myQueryName(i - 1)). _
                Cells(Rows.Count, 1).End(xlUp).Row
            Worksheets(myQueryName(i - 1)) _
                .Cells(2, 1).Formula = _
                "=COUNT(A4:A" & myRow & ")"
            ~ 略(その他のセルに計算式を代入) ~
        Next i
        .CloseCurrentDatabase
        .Quit
    End With

    Set CQRecodeSset = Nothing
    Set AccessApp = Nothing

End Sub

 (2)でクエリーの名前を配列変数に代入します。Variant型の変数とArray関数を組み合わせると,1行(リスト1は画面の都合で改行しています)のステートメントで配列変数に複数の要素を代入できます。

 文字列型変数にDBのファイル名を代入します(3)。OpenCurrentDatabaseメソッドでDBファイルを開きます(4)。ファイル名はフルパスを付けて指定します。クエリーを実行するのが(5)です。ループの中で,クエリーの名前を変更しながら10個のクエリーを順次実行します。DoCmdオブジェクトはメソッドの集合体です。

 クエリーを実行して作成されたレコードセット(OpenRecordsetメソッドの戻り値)をオブジェクト型変数に代入します(6)。これにより,クエリーで作成したデータ(レコード)を取り出せるようになります。

 (7)でレコードセットの中から,レコードを一つずつ取り出すループを構成しています。(10)のMoveNextメソッドで順次レコードを取得します。レコードの最後にたどり着くとEOF関数がTrueを返します。(9)では,取り出したレコードの各フィールドのデータをワークシートのセルにコピーしています。ループのカウンタをフィールドとセルの列番号に利用することで,複数のフィールドのデータを各セルに配分しています(8)。

 (11)でクエリーを閉じます。Closeメソッドは,第1引数にオブジェクトのタイプを,第2引数にオブジェクトの名前を指定します。

 ワークシートに転記したデータの末尾の行番号を取得して,変数に代入します(12)。この変数の値は,各セルに計算式を代入する(13)のステートメントで利用します。セルに計算式を代入するには,Formulaプロパティを使います。代入するのは,アンケートの回答をカウントする計算式です。これで,マクロの実行が終了した直後にカウントも完了しています。

 最後に(14)でデータベースを閉じ,(15)でAccessを閉じます。今回のサンプルはAccessのVisibleプロパティをTrueにセットしていないので,マクロ実行時にAccessはまったく画面に表示されません。マクロの経過をチェックしたい場合は,適当なところでVisibleプロパティをTrueにセットしてから画面で確認してください。

古庄 潤