今作成したメインプロシージャのすぐ下に、Functionプロシージャ「RunQuery」を作成します。
このプロシージャは、引数に文字列型の「IPTData」という変数を組み込みます。また、プロシージャの戻り値は、クエリーの成功か失敗かという2通りしか設定しませんので、論理型(Boolean)で指定しておきます。
Function RunQuery(ByVal IPTData As String) As Boolean
End Function
続いて、プロシージャの先頭で変数を宣言します。最初の4つは、データベースの操作に使用する変数で、すでにプロシージャ「データベース接続テスト」で使用したものと同じデータ型を使用します。Dim WSP As Workspace
Dim DB As Database
Dim TBL As Recordset
Dim Fname As String
さらにこれらの変数に加え、クエリー実行用に使用する変数を3つ宣言します。Dim QString As String ―
Dim NewQRY As QueryDef ―
Dim QResult As Recordset ― 
変数が用意できたら、データベースを開く操作をします。この処理も、すでにプロシージャ「データベース接続テスト」で行なった処理と同じです。ワークスペースを作成し、データベースファイルを開き、テーブルを開きます。それぞれ作成したオブジェクトは、Setステートメントを使って、宣言してあるオブジェクト変数に格納しておきます。
Fname = ActiveWorkbook.Path & "¥Club.mdb"
Set WSP = CreateWorkspace("", "admin", "", dbUseJet)
Set DB = WSP.OpenDatabase(Fname, False)
Set TBL = DB.OpenRecordset("会員名簿", dbOpenTable)
今度は、クエリーを実行するために使用するSQL文字列を作成します。DAOを使用したデータベース操作は、SQLステートメントを使用したクエリー操作が基本になります。そして、DAOで使用できるSQLステートメントは、標準SQL(ANSI SQL)とその拡張機能です。
このマクロでは、インプットボックスで入力された月名を使って、テーブル「会員名簿」にあるフィールド「入会年月日」から一致する月名を抽出する、という処理を行ないます。この操作を行なう基本的なSQLステートメントは、「Select」「From」「Where」です。Selectステートメントのあとに、抽出するテーブル名とフィールド名を指定します。そして、Fromステートメントのあとに抽出データのあるテーブル名を指定し、Whereステートメントで検索対象のフィールド名を指定します。
ここでは、抽出するフィールドは「会員No」「氏名」「入会年月日」「住所1」の4つなので、これをテーブル名「会員名簿」を「.」でつないでSelectステートメントの後ろに記述します。
QString = "Select 会員名簿.会員No,会員名簿.氏名,会員名簿.入会年月日,
会員名簿.住所1
取り出すテーブル名は「会員名簿」なので、Fromステートメントでこのテーブル名を指定します。From 会員名簿
検索対象のフィールドは「入会年月日」なので、Whereステートメントでこのフィールドを、テーブル名をつけて指定します。Where 会員名簿.入会年月日
検索を行なうには、SQLステートメントの「演算子」を使用します。Like '08'
と記述してクエリーを実行すると、「08」が含まれる値を検索して抽出してきます。また、ワイルドカード「*」と組み合わせて使用すると、その文字を含む文字列を探し出すことができます。例えば、Like '08*'
と実行すると、先頭が「08」ではじまる文字列を検索します。Like '*08*'
と記述します。文字列の先頭は年を表わす数字になっていますが、「99/08」も「98/08」も検索したいので、「*08*」というように、月数「08」の含まれるデータが検索一致データとなるようにします。しかし、これだと「99/11/08」のように日付が「08」のデータも検索されてしまう可能性があります。そこで、月数の前後にある「/」も検索対象の文字列に含め、Like '*/08/*'
とすると、「/08/」が含まれる文字列だけが一致するデータになり、検索対象を月数に限定することができます。
すでに、メインのプロシージャにあるInputBox関数とその後の文字列処理によって、このLike演算子に使用する検索文字列は作成されています。そして、その文字列はこのFunctionプロシージャ「RunQuery」の引数に設定した変数「IPTData」を使って、プロシージャに渡されます。そこで、Like演算子に、変数「IPTData」をセットすれば、インプットボックスに入力した月数でSQL文字列を作成することができます。
Like IPTData
しかし、上記の記述ではクエリーに失敗します。なぜなら、変数名が文字列で作成されてしまうからです。QString = "Select 会員名簿.会員No,会員名簿.氏名,会員名簿.入会年月日,
会員名簿.住所1 From 会員名簿 Where 会員名簿.入会年月日
Like IPTData"
これでは、変数名「IPTData」が文字列として指定されてしまい、Like演算子は「IPTData」という文字列を含むデータを検索してしまうからです。Like" & "'" & IPTData & "'"
ちょっとわかりづらい記述ですが、「Select」から「Like」までをひとつの文字列で一度作成し、その後ろに「'」を付けて変数「IPTData」を指定し、最後にもう一度「'」を付けてあげます。QString ="Select 会員名簿.会員No,会員名簿.氏名,会員名簿.入会年月日,
会員名簿.住所1 From 会員名簿 Where 会員名簿.入会年月日
Like" & "'" & IPTData & "'"
という記述になります。「"Select」から始まり最後の「" ' "」までを、改行を入れずに1行で記述します。QString = "Select 会員名簿.会員No,会員名簿.氏名,会員名簿.入会年月日,
会員名簿.住所1 From 会員名簿 Where 会員名簿.入会年月日
Like'*/07/*'
という文字列に変換されて認識されるようになります。
クエリーのためのSQL文字列が作成できたら、この文字列を使って実際にクエリーを実行します。
DAOでクエリーを実行するには、RecordsetオブジェクトのCreateQueryDefメソッドを使用します(書式5)。このメソッドは、QueryDefオブジェクトを作成するメソッドで、クエリーの操作はこのオブジェクトを介して行なうことになります。
書式5:CreateQueryDefメソッドの書式
|
CreateQueryDefメソッドは、2つの引数をもちます。最初の引数に、作成するQueryDefオブジェクトの名前を指定します。2番目の引数に、実行するSQLステートメントを指定します。メソッドが実行されると、SQLステートメントにもとづきクエリーが実行され、QueryDefオブジェクトが作成されてそのオブジェクト名が返されます。
最初の引数に名前を指定しないと、作成されたQueryDefオブジェクトは一時的なものになり、プロシージャの終了とともに抹消されます。とりあえずここでは、一時的なQueryDefオブジェクトとしてクエリーを実行することにします。
Set NewQRY = DB.CreateQueryDef("", QString)
このメソッドでクエリーが実行され、結果は作成されたQueryDefオブジェクトにクエリーテーブルとして作成され、Recordsetオブジェクトとして格納されています。Set QResult = NewQRY.OpenRecordset()
これで、クエリー結果をテーブルの操作と同じような操作でアクセスできるようになります。
クエリー結果を操作する前に、クエリーが失敗した時のためのエラー処理を作成しておきます。
QueryDefオブジェクトの中のRecordsetオブジェクトの、「RecordCount」プロパティを調べると、作成されたクエリーテーブルにレコードがあるかどうかを把握できます。この値が「0」であれば、クエリーテーブルのレコードが0件ということで、一致する条件のデータが見つからなかったということになりますので、クエリーが失敗したとみなし、このプロシージャの戻り値に「False」をセットしプロシージャを終了します。
If QResult.RecordCount = 0 Then
MsgBox "該当データがありません"
RunQuery = False
Exit Function
End If
RecordCountプロパティの値が「0」でなければ、少なくとも1件のレコードがクエリーテーブルにあることになりますので、今度はその件数を把握します。
クエリーテーブルの場合は、Accessのテーブルのようにテーブルを開いた時点でRecordCountプロパティに、総レコード数が格納されているわけではありません。一度、「MoveLast」メソッドを使用して最後尾のレコード位置にカレントレコードを移動させます。こうすることで、「RecordCount」プロパティには全レコード数が格納されますので、クエリーによる抽出結果の総レコード数を把握できます。そして、その数をメッセージボックスで表示するようにします。
QResult.MoveLast
MsgBox QResult.RecordCount & "件のデータを抽出しました。"
テーブルのレコードには、現在アクティブになっているレコード、カレントレコードがあります。しかし、レコードの先頭が常にカレントレコードであるとは限りません。そこで、このカレントレコードの位置を操作するメソッドがいくつか用意されています。
一方、テーブルからレコードデータを取得するには、一度特定のレコードにカレントレコードを移し、その位置から指定するフィールドデータを取り出します。
先頭のレコード位置にあるデータを取り出したければ、一度MoveFirstメソッドでカレントレコードの位置をレコードの先頭にもってゆき、そこからFieldsコレクションオブジェクトのValueプロパティの値を取得します。先頭から2番目のレコード値のデータを取り出したい場合は、MoveNextメソッドで、カレントレコードを次のレコード位置に移動し、FieldsコレクションオブジェクトのValueプロパティの値を取得します。
この方法を使用し、For...Nextステートメントで、「1」から「RecordCount」プロパティの値までループを繰り返せば、クエリー結果の全件のレコードデータを取得できます。
まず、MoveFirstメソッドで、カレントレコードを先頭のレコード位置に移動します。
QResult.MoveFirst
次に、For...Nextループ内でMoveNextメソッドを使って、カレントレコード位置をひとつずつ移動させながら、FieldsコレクションオブジェクトのValueプロパティの値を、ワークシート「Sheet2」のセルに転送してゆきます。With Worksheets("Sheet2")
For i = 1 To QResult.RecordCount
.Cells(i, 1) = QResult.Fields(0).Value
.Cells(i, 2) = QResult.Fields(1).Value
.Cells(i, 3) = QResult.Fields(2).Value
.Cells(i, 4) = QResult.Fields(3).Value
QResult.MoveNext
Next
End With
たとえば、インプットボックスに「08」と入力してクエリーを実行すると(検索文字列は「*/08/*」)、「98/08/07」「98/08/11」「98/08/12」の3件のデータが抽出され、これらのレコードの「会員No」「氏名」「入会年月日」「住所1」の4つのフィールドデータが、ワークシートSheet2に転送されます。
クエリーが成功したら、Functionプロシージャの戻り値に「True」をセットし、開いた各テーブル、データベースファイル、ワークスペースを閉じます。この時、クエリーで作成したクエリーテーブルも閉じることを忘れないでください。
RunQuery = True
QResult.Close
TBL.Close
DB.Close
WSP.Close
最後に使用したオブジェクト変数にNothingを代入して、プロシージャを終了します。Set QResult = Nothing
Set TBL = Nothing
Set DB = Nothing
Set WSP = Nothing