まずマクロを分けるために、プロジェクトにもうひとつ標準モジュール(Module3)を追加します。
そして、標準モジュール「Module3」の宣言セクションに、次のユーザー定義のデータ型を宣言します。
Type CustData
Id As String
jusyo As String
simei As String
hizuke As String
End Type
このユーザー定義のデータ型の各要素は、上から順番に「会員番号」「住所」「氏名」「入会年月日」を格納する変数です。すべて、データベースのデータと同じ文字列型で宣言します。Dim QueryData() As CustData
なぜなら、クエリーの実行結果で抽出されるレコード数は、クエリー結果によって異なるからです。1件の抽出があれば、3件の抽出もありうるわけですから、いくつの配列を必要とするかは、クエリーの結果を見てから決定するようにします(これを配列の動的確保と言います)。そのため、この時点では要素数をもたない配列として宣言しておきます。Dim Rcdcnt As Integer
メインのプロシージャは特に変更ありませんので、そのままにしておきます。なお、このマクロでは、先に作成したマクロと内容が混乱しないように、すべてのプロシージャ名を「xxx2」に変更しています。
Sub 案内状2()
Dim IPTData As String
IPTData = _
InputBox("作成する月名を入力してください。", "案内状作成")
IPTData = "*/" & IPTData & "/*"
If RunQuery2(IPTData) = True Then
Call 案内状作成2
End If
End Sub
今度は、クエリーを実行するFunctionプロシージャ「RunQuery」を修正し、「RunQuery2」にします。これにより、プロシージャの戻り値を格納する変数も「RunQuery」から「RunQuery2」に変更します。
If QResult.RecordCount = 0 Then
MsgBox "該当データがありません"
RunQuery2 = False
Exit Function
End If
............
............
............
RunQuery2 = True
クエリーを実行し、OpenRecordsetメソッドを実行してクエリーテーブルを開いたら、MoveLastメソッドでカレントレコード位置をクエリーテーブルの最後尾に移動します。そして、全レコード数をRecordCountプロパティから取得し、モジュールレベルで宣言した変数「Rcdcnt」にいったん格納します。
QResult.MoveLast
Rcdcnt = QResult.RecordCount
そしてこの変数を使って、メッセージボックスで抽出データの件数を表示します。MsgBox Rcdcnt & "件のデータを抽出しました。"
次に、クエリーテーブルからレコードデータを取得する処理を行ないますが、この部分をすべて修正し、ワークシートに転送するのではなく、配列で宣言したユーザー定義型変数「QueryData()」に格納するようにします。
まず、ReDimステートメントで抽出データを格納するユーザー定義型変数「QueryData」に、配列の要素数を指定して再宣言します。
抽出レコードの総数は、変数「Rcdcnt」に格納されていますので、この数字分だけ配列を確保すればいいことになります。そこで、配列の要素数に変数「Rcdcnt」を指定し、ReDimステートメントで配列数を決定します。キーワード「Preserve」を付けると、直前の配列数を動的に変更することができます。
ReDim Preserve QueryData(Rcdcnt)
これで、変数「QueryData」は、クエリー結果の全レコード分の配列が確保されました。QResult.MoveFirst
For i = 1 To Rcdcnt
With QueryData(i)
.Id = QResult.Fields(0).Value
.simei = QResult.Fields(1).Value
.hizuke = QResult.Fields(2).Value
.jusyo = QResult.Fields(3).Value
End With
QResult.MoveNext
Next
例えば、クエリーの結果、3件のレコードが抽出されれば、変数「QueryData」は「QueryData(3)」という配列数で再度宣言され、「QueryData(1)」に1件目のレコードデータが、「QueryData(2)」に2件目のレコードデータが格納されるようになります。
これで、クエリーによる抽出結果のデータを全件、ユーザー定義型の変数「QueryData」に格納しました。あとは、ここからデータを取り出して、案内状の作成に使用するだけです。
プロシージャ「案内状作成2」は、基本的にはワークシートからデータを取り出して案内状を作成する処理と同じですが、データの取り出し元がセルではなく変数「QueryData」になっている点が違います。
また、ここではループを使用して、抽出した全員分の案内状を一気に作成してしまいます。この時、ワークシート名に変数を使用して、「作成1」「作成2」「作成3」と番号を組み合わせた名前にしています(図9)。
図9:抽出した全員分の案内状をいっきに作成 |
![]() |
Sub 案内状作成2()
Dim i As Integer
For i = 1 To Rcdcnt
Worksheets("案内状原紙").Copy _
After:=Worksheets("Sheet3")
With ActiveSheet
.Name = "作成" & i
.Range("B1") = QueryData(i).Id
.Range("A3") = QueryData(i).jusyo
.Range("C4") = QueryData(i).simei
End With
Next
End Sub
![]() |
この例では、ReDimステートメントによって「QueryData(3)」と再宣言していますが、これだと配列の要素は4つ確保されます。「QueryData(0)」から「QueryData(3)」の4つということです。 一方、レコード番号は「1」から始まりますので、配列の添え字とレコード番号を一致させるために、「QueryData(0)」は使わず、「QueryData(1)」からデータを格納するようにしています。使わない配列をひとつ余分に宣言するため、メモリの無駄な消費になりますが、わかりやすいコードにするためにあえてこのような処理にしています。 |