この特集のトップページへ
Chapter 7:プレゼンテーション層の構築

7.4.6 顧客の検索
●[検索]ボタンが押されたときの処理

○フィールドが日付の場合
 では,フィールドが文字列か数値かという分岐だけで十分かというと,実はそうではない。今回作成しているアプリケーションには,“作成日”や“最終更新日”などの日付要素も含まれている。よって日付も検索できなければならない。

 とはいえ日付の検索は,さほど難しくはない。全体を“#”で括って指定するだけである。たとえば,次のような具合になる。

g_objRec.Find "LASTDATE = #2000-07-10#", _
              1, adSearchForward

One Point! 日付の場合には,“#”で括る表記以外に,文字列と同じように“'”で括る表記も許される。どちらを使ってもよい。

 上記のようにFindメソッドを呼び出す場合,LASTDATEフィールドの値が「2000-07-10」と一致するものを検索の対象としている。しかし,この条件を厳密にいえば,LASTDATEフィールドの値が「2000-07-10 00:00:00」と一致するものを指す。つまり,時刻も検索の対象となってしまう。そのため,LASTDATEフィールドの値が「2000-07-10 00:01:10」や「2000-07-10 10:12:13」であるレコードは,条件と一致しないことになる。したがって,「2000-07-10 10:12:13」に合致したいものを検索する場合には,次のようにしなければならない。

g_objRec.Find "LASTDATE = #2000-07-10 10:12:13#", _
              1, adSearchForward

 これは,ユーザーに時刻まで正確に入力してもらわなければならないということを意味する。いうまでもなく,そういったシステムは極めて使いづらい。ユーザーが“2000-07-10”と入力したならば,時刻は無視して日付さえ合致すればよい,ということにしたい。

 そのためには,概念的には次のようにすればよい。

g_objRec.Find _
    "LASTDATE >= #2000-07-10#" AND LASTDATE < #2000-07-11#"
    1, adSearchForward

 この場合は,LASTDATEフィールドの値が2000-07-10以上かつ2000-07-11未満のものを検索するという意図である。つまり,LASTDATEフィールドの値が「2000-07-10 00:00:00」〜「2000-07-10 23:59:59」の範囲であるものを検索対象としようとしているのである。

 しかし,残念ながらFindメソッドはAND演算子をサポートしないために,上記の検索条件はエラーとなる。そこでやむなく,次のようなループ処理として実装する。

' LASTDATEフィールドの日付が2000-07-10であるものを検索する
Do
    ' LASTDATEが2000-07-10以上であるものを検索
    g_objRec.Find "LASTDATE >= #2000-07-10#", _
                  1, adSearchForward
    If Not (g_objRec.EOF Or g_objRec.BOF)
        ' 見つかったものが2000-07-11未満かどうか
        If g_objRec.Fields("LASTDATE") < #2000-07-11# Then
            ' この場合,LASTDATEフィールドの値は
            ' 2000-07-10〜2000-07-11の範囲にある
            ' つまりLASTDATEフィールドの日付部分は2000-07-10である
            Exit Do
        End If
    End If
Loop While Not (g_objRec.EOF Or g_objRec.BOF)
' ここで,g_objRec.EOFまたはg_objRec.BOFが
'  Trueであれば見つからなかった
' 見つかっていれば,該当レコードがカレントレコードになっている

 少々複雑ではあるが,原理は簡単である。LASTDATEフィールドの値のうち,日付部分が2000-07-10であるものを検索するには,まずFindメソッドを使って“LASTDATE >= #2000-07-10#”という条件を指定し,LASTDATEフィールドの値が2000-07-10以上であるものを検索する。次に,検索した結果,LASTDATEフィールドの値が2000-07-11未満であれば,そのレコードはLASTDATEフィールドの日付部分が2000-07-10なので,ループを抜ければよい。そうでなかった場合(たとえば,2000-07-13や2000-07-14などが抽出された場合)には,再検索するというループ処理をする。

 このように,Findメソッドは複数列の検索をサポートしない。そのため,複雑な条件を検索したい場合には,まず1つ目の条件でFindメソッドを実行し,それに合致したならば2つ目の条件に合致するかどうかを調べるといった手法をとる必要がある。しかし,処理の複雑化ならびにループ処理は速度の低下を招く結果になるので,Findメソッドに頼りすぎるのは好ましくない。複雑な条件を指定したいのであれば,Findメソッドを使うのではなく,検索条件をWHERE句に指定したSELECT文をデータベースに対して実行して結果を取得するようにしたほうが効率がよい(もちろん,N階層アプリケーションモデルの場合には,そういった機能を備えたビジネスロジックを実装するという意味である。データベースに直接SELECT文を発行するという意味ではない)。

 今回は,(1)ビジネスロジックを構築し直す手間がかかる,(2)日付による検索はあまり頻繁にしないだろうから多少の速度劣化には目をつむる,という2つの理由から,上記のループ処理による検索手法をとることにする。しかし,効率を考えた場合には好ましくないということを,頭の片隅にでも入れておいてほしい。


One Point! 複数列を検索する場合には,Sortプロパティを使って特定列で並び替えてからFindメソッドで検索する,という手法はよい考えである。たとえば,上記のようにLASTDATEフィールドの値が2000-07-10〜2000-07-11のあいだであるものを検索する場合,先にSortプロパティを用いてLASTDATEフィールドの順番で並び替えておけば,ループ処理内で2000-07-11を越えるフィールドが見つかった段階でループ処理を打ち切ってしまえばよいので,全レコードを検索する必要がなくなり,処理時間を向上させることができる。また,Filterプロパティを使うという考えもある。Filterプロパティは,特定の条件に合致するレコードだけに絞り込む機能を提供する。Filterプロパティは,Findメソッドと違い,複数の条件を指定できる。たとえば,Filterプロパティに“LASTDATE >= #2000-07-10# AND LASTDATE < #2000-07-11#”と設定すると,LASTDATEフィールドの値が2000-07-10〜2000-07-11以外のレコードが見えなくなる。こうした状態でカレントレコードを1つずつ進めてゆけば,LASTDATEフィールドの値が2000-07-10〜2000-07-11であるレコードを次々と取得してゆくことができる。Filterプロパティについての詳細は,ADOのドキュメントを参照してほしい。
prevpg.gif Chapter 7 33/65 nextpg.gif