トーマス リッツォ
Microsoft(R) Exchange Server は当初から、構造化されていない大容量のデータ ストレージの操作を非常に得意としてきました。ただしこのようなデータを操作するためには、これまではバージョン 1.21 以前の Collaboration Data Objects ( CDO )か、Microsoft Outlook(R) を使用しなければなりませんでした。Microsoft の Universal Data Access ( UDA )戦略の基本的な考えは、OLE DB を通じて、データ コンシューマが ActiveX(R) Data Objects ( ADO )を使ってアクセスできる行セットに、タイプの異なるさまざまな種類のデータを公開しようというものです。
Exchange 2000 Server は、UDA 戦略と Exchange 2000 への OLE DB プロバイダの導入を組み合わせたものです。ADO 2.5 には、このデータ プロバイダが公開するデータにアクセスするための Record オブジェクトと Stream オブジェクトが含まれています。
Exchange 2000 Server のデータは、各種 Microsoft 製品の共通データ ストアに間もなくなる予定の、Web Storage System に格納されます。Exchange 2000 Server は、データ リポジトリとして Web Storage System を使用する最初の Microsoft 製品です。
ADO 2.5
URL によるアドレス指定
ADO 2.5 では、接続文字列とコマンド テキストの代わりに、Uniform Resource Locator (URL)が使用できるようになりました。Web Storage System ではすべてのアドレスを URL で指定できるため、ADO 呼び出しに URL を渡すだけで、フォルダ、メッセージ、予定、ドキュメントなど、Web Storage System 内のあらゆるリソースに ADO を使用してアクセスできます。
Record オブジェクト
Record オブジェクトは、ADO 2.5 で新たに追加されました。この Record オブジェクトを使用して、Web Storage System 内のあらゆる項目にアクセスできます。項目のプロパティ セットや関連するストリームも完全にアクセスできます。たとえばサーバー myserver のユーザー別名 userx の受信トレイ inbox にある項目 item には、次のコードでアクセスできます。
Set Rec = CreateObject("ADODB.Record")
strURL = "http://myserver/exchange/userx/inbox/item"
Rec.Open strURL
Stream オブジェクト
同じく ADO 2.5 で新たに追加された Stream オブジェクトは、ファイルまたはメッセージを構成するバイナリ ストリームまたはテキスト ストリーム(たとえば添付ファイル)にアクセスします。Web Storage System のように階層構造を持つデータ ストアのレコードには、メッセージの内容を格納した既定のバイナリ ビット ストリームを関連付けることができます。これらのデータ ストリームを格納したフィールドを、Stream オブジェクトを使用して操作できます。次のコードは、オブジェクトの参照をストリームへ設定する方法の 1 つを示します。
Set S1 = CreateObject("ADODB.Stream")
Set S1 = Rec.Fields(adDefaultStream)
スキーマ
Web Storage System スキーマ
Web Storage System は、リソースのスキーマ情報を定義する手段になります。Web Storage System のスキーマ機能を使用することにより、アプリケーションのスキーマ情報を、Web Storage System の SQL クエリ プロセッサのようにスキーマを認識する他のアプリケーションが検出できるようにすることができます。
Web Storage System のスキーマ情報は、Microsoft SQL Server(TM) のようなリレーショナル データベース システムほど厳密なものではありません。その代わり Web Storage System のスキーマ情報は、スキーマを認識するアプリケーションが、特定のアプリケーションの項目のコンテンツ クラスの名前とそのプロパティを認識するためのメカニズムとなります。スキーマの使用により、互換性と再利用性が向上します。
Web Storage System のスキーマ情報を定義するには、プロパティとコンテンツ クラスの定義を使用します。これらの定義は通常、指定されたスキーマ フォルダの項目として存在しています。図 1に、Web Storage System を使用した典型的なアプリケーションの例を示します。
.jpg)
図 1 :スキーマ フォルダ
図 1では、スキーマ フォルダはアプリケーション フォルダのサブフォルダです。プロパティとコンテンツ クラスはスキーマ フォルダに入っています。アプリケーション フォルダとスキーマ フォルダの階層は任意の順序で編成できますが、管理とデバッグが複雑にならないように、配置はできる限り簡潔にしておく必要があります。
プロパティ定義
プロパティ定義は、プロパティのスキーマ情報を格納する項目であり、通常は指定されたスキーマ フォルダに作成します。プロパティ定義を作成するには次のように定義を入れる項目を作成し、それに名前とデータ型を割り当て、コンテンツ クラスをurn:content-classes:propertydef として指定します。
Rec.Open strURL & "title",,adModeReadWrite, adCreateNonCollection
Set Flds = Rec.Fields
With Flds
.Item("DAV:contentclass") = "urn:content-classes:propertydef"
.Item("urn:schemas-microsoft-com:xml-data#name") = "urn:schemas-microsoft-com-book:title"
.Item("urn:schemas-microsoft-com:datatypes#type") = "string"
.Item("urn:schemas-microsoft-com:exch-data:ismultivalued") = False
.Item("urn:schemas-microsoft-com:exch-data:isindexed") = True
.Item("urn:schemas-microsoft-com:exch-data:isreadonly") = False
.Update
End With
Rec.Close
コンテンツ クラス定義
コンテンツ クラスは、生データとスキーマを結び付けます。Exchange データ ストアのどのリソースにも、対応するコンテンツ クラスがあります。また、どのコンテンツ クラスにも、リソースを解析するためのスキーマがあります。コンテンツ クラス定義(通常は指定のスキーマ フォルダにある項目)の中には、次の情報を指定するためのプロパティがあります。
- コンテンツ クラスの名前
- コンテンツ クラスに属する個々のプロパティ
- 既定のプロパティの継承元となる既存のコンテンツ クラス(複数も可)
- フォルダ コンテンツ クラスでは、想定しているフォルダ項目のコンテンツ クラス
コンテンツ クラスにカスタム プロパティを追加することもできます。たとえば、コンテンツ クラスを連絡先管理アプリケーション用に拡張するには、urn:content-classes:person のようにします。
フォルダと項目へのコンテンツ クラスの追加
項目のコンテンツ クラスを指定するには DAV:contentclass プロパティを使用します。特定の項目に対して指定されたコンテンツ クラスの要素としてリストされたプロパティはすべて、その項目のスキーマに統合されます。これらのプロパティを、項目のフォルダ内のすべてのプロパティを対象とする SQL 検索で返されるようにするには、フォルダのコンテンツ クラス定義のurn:schemas-microsoft-com:exch-data:expected-content classプロパティで想定されているコンテンツ クラスの中に、コンテンツ クラスをリストしなければなりません。
スキーマ スコープ
プロパティ定義を作成する項目が入っているアプリケーション フォルダは、schema-collection-ref(SCR)プロパティがスキーマ フォルダの URL に設定されています。この SCR プロパティは、パーサがスキーマ情報の検索を開始する場所を表しています。このフォルダの多値プロパティ baseschema には、コンテンツ クラスとプロパティ定義を検索する別の場所を指定する、same-store フォルダの URL が入ります。
Web Storage System への接続
接続
前述の通り、ADO を使用して Web Storage System のあらゆるリソースにアクセスできます。Web Storage System 内のリソースにアクセスするための第 1 歩は、Web Storage System 自体をデータソースとして、暗黙的または明示的に接続することです。URL の形式としては FILE: 型の URL と、HTTP: 型の URL の 2 通りを選択できます。
暗黙の接続
Exchange 2000 の OLE DB プロバイダは OLE DB ルート バインダに、FILE: OLE DB URL 名前空間を登録します。したがって FILE: 型の URL を使用して Web Storage System に接続するとき場合は ADO 接続は暗黙であり、Web Storage System 内のリソースにアクセスする場合にプロバイダを明示的に指定する必要がありません。
次の例では、ユーザー userx の inbox の項目にアクセスしています。
Set Rec = CreateObject("ADODB.Record")
strURL = "file://./backofficestorage/myserver.com/MBX/userx/inbox/item.txt"
Rec.Open strURL
明示的な接続
HTTP: URL 形式を使用して Web Storage System のリソースにアクセスするときの規則は、ネットワークを通じて項目にアクセスするときと同じです。URL の形式は次の通りです。
http://servername/virtual-directory/virtual-path
- Exchange。すべてのプライベート ストアの既定の仮想ディレクトリ名。
- Public。デフォルトのパブリック フォルダ階層内の最上位パブリック フォルダの仮想ディレクトリ名。
HTTP URL を使用して Web Storage System にアクセスするには、項目のバインディングのときに、Exchange 2000 バインダの OLE DB プロバイダを明示的に指定する必要があります。これを行うには、ADO Connection オブジェクトの Provider プロパティを ExOLEDB.DataSource に設定して、Connection オブジェクトを Record オブジェクトの Open メソッドにパラメータとして渡します。たとえば次のコードは、先に FILE: URL 形式を使用してアクセスしたものと同じ項目を、今度は HTTP: URL 形式を使用してアクセスしています。
Set Conn = CreateObject("ADODB.Connection")
Set Rec = CreateObject("ADODB.Record")
Conn.Provider = "ExOLEDB.DataSource"
strFolderURL = "http://myserver/exchange/userx/inbox"
Conn.Open strFolderURL
Rec.Open strFolderURL & "/item.txt", Conn
Web Storage System の理解
階層的でリレーショナルなデータ ストア
リレーショナル データ ストアは通常はデータベースで構成され、データベースにはテーブルが含まれています。さらにテーブルにはレコードが含まれており、レコードにはフィールドが含まれています。データは構造化されており、データベースに格納できるデータの種類に関しては、スキーマは非常に厳密に管理されています。リレーショナル データ ストアの例としては、メインフレームの ISAM/VSAM データベースや SQL サーバー データベースなどがあります。リレーショナル ストアのテーブル中のデータは、Open Database Connectivity (ODBC)プロバイダまたは OLE DB プロバイダを使用して、行セットとして表すことができます。行セットでは各行がレコードを表します。
ビジネス情報を保存するときには、しばしば高い柔軟性が求められます。階層型のデータ ストアは、スキーマに融通性を持たせることによってこの要求を満たします。階層型のデータ ストアは、電子メール、バイナリ ファイル、テキスト ファイル、画像データ、地理データ、その他のカスタム ビジネス オブジェクト用に設計されたデータ ストアと同じように柔軟性が高く、構造を持たない非定型のデータを受け付けることができます。なぜならスキーマに十分な融通性があり、特定のプロパティが、その定義方法に応じて必要であったり不要であったりする場合も柔軟に対応できるからです。
リレーショナル データ ストアと同じく、階層型のデータ ストアも OLE DB プロバイダを使用してデータを表現できます。プログラムの中で ADO を使用して、OLE DB プロバイダが供給するデータを利用(または消費)できます。ADO 2.5 には、特に階層型のデータにアクセスする目的で設定された Record と Steam という新しいオブジェクトが追加されています。Record オブジェクトはフォルダと項目といったリソースにアクセスでき、Stream オブジェクトは、ファイルやメッセージを含むバイナリ ビット データにアクセスできます。
フォルダと項目の検索
Web Storage System 内の情報は、プライベート データ ストアとパブリック データ ストアの複数のデータベースの隅々まで配信されます。一方それらのデータベースには複数の関連テーブルが入っています。たとえば Folders テーブルには複数のフォルダが記録され、別のテーブルには 1 つのフォルダ内の一連の項目が記録されます。
Recordset オブジェクトはこれらのテーブルを表し、Record オブジェクトはフォルダや項目などの個々のレコードを表します。Web Storage System は階層型データベースに基づいているため、フォルダと項目はどちらも Record と Recordset で表すことができます。URL と ADO オブジェクトを組み合わせれば、Web Storage System のコンテンツにアクセスしたり、それらを制御したりできます。
フォルダ階層間の移動
次の例では、フォルダを表す Recordset オブジェクトと、サブフォルダ(直下のサブフォルダと、さらにそれ以降のサブフォルダ)を列挙する SQL クエリ使用しています( Conn は Web Storage System への有効な接続オブジェクトであると想定しています)。
strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""
strQuery = strQuery & " FROM SCOPE('shallow traversal of """ & URL & """')"
strQuery = strQuery & " WHERE ""DAV:isfolder"" = True AND "
strQuery = strQuery & """DAV:ishidden"" = False"
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open strQuery, Conn
前の例に示した URL には、任意のフォルダの URL を指定できます。生成される Recordset オブジェクトには、それぞれがサブフォルダを表すレコードが含まれます。たとえば Test という名前のパブリック フォルダが、パブリック フォルダ システムのルートにあるとします。この URL は http://myserver/public/Test になります。Test には First と Second という 2 つのサブフォルダも入っています。前の例で URL に Test を使用すると、2 つのレコードが入った Recordset オブジェクトが作成されます。レコードは 2 つのサブフォルダを表し、ADO Record オブジェクト参照を割り当てることができます。
次に例を示します。
Set Rec1 = CreateObject("ADODB.Record")
Set Rec2 = CreateObject("ADODB.Record")
Rec1.Open Rs 'Subfolder "First"
Rs.MoveNext
Rec2.Open Rs 'Subfolder "Second"
サブフォルダへの Record オブジェクト参照を割り当てたら、前述の例と同じようにフォルダの絶対 URL が格納されている DAV:href フィールドと、先述の SQL クエリを使用してサブフォルダを列挙できます。モジュール性を高めて再利用しやすくするために、クエリの例を 1 つの関数にカプセル化し、関数を再帰的に呼び出してフォルダ構造全体を列挙できます。
フォルダの検索
今述べた考え方に、適当なツリー トラバース アルゴリズムを組み合わせれば、MAPI クライアントで使用するために Microsoft Exchange 2000 Server によってインストールされる既定のパブリック データ ストア階層にあるフォルダ( All Public Folders )を検索できます。プライベート データ ストアや既定以外のパブリック データ ストア内のフォルダを検索する場合は、次のクエリを使用できます。
strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""
strQuery = strQuery & " FROM SCOPE('deep traversal of """ & URL & """')"
strQuery = strQuery & " WHERE ""DAV:isfolder"" = True AND "
strQuery = strQuery & """DAV:ishidden"" = False"
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open strQuery, Conn
トラバースの深さに注目してください。これによりすべてのサブフォルダが検索範囲に含まれます。Web Storage System 内のリソース検索に深いトラバースを使用した場合と浅いトラバースを使用した場合の比較や、WHERE 句を使用して探索結果を絞り込む方法については本稿で後述します。
フォルダ内の項目のリスト
前述の例に似たクエリを使用して、フォルダ内に含まれている項目を列挙できます。
次の例のようにします。
strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""
strQuery = strQuery & " FROM SCOPE('shallow traversal of """ & URL & """')"
strQuery = strQuery & " WHERE ""DAV:isfolder"" = False AND "
strQuery = strQuery & """DAV:ishidden"" = False"
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open strQuery, Conn
条件文 DAV:isfolder = False により、検索対象のフォルダからフォルダ以外の項目だけを返すように、クエリ プロセッサに指示しています。レコードセット全体をループ処理すれば、項目のプロパティを表示できます。
例を次に示します。
Do While Not (Rs.BOF Or Rs.EOF)
Debug.Print Rs.Fields("DAV:displayname")
Rs.MoveNext
Loop
リストの範囲の限定
WHERE句に条件を追加することで、検索結果に返される項目やフォルダの範囲を絞り込むことができます。たとえば先に示した例に次のようにコードを挿入すれば、特定のフォルダ内のメッセージを除くドキュメントだけを検索できます。
strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""
strQuery = strQuery & " FROM SCOPE('shallow traversal of """ & URL & """')"
strQuery = strQuery & " WHERE ""DAV:isfolder"" = False AND "
strQuery = strQuery & """DAV:ishidden"" = False AND "
strQuery = strQuery & """DAV:contentclass"" = 'urn:content-classes:document'"
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open strQuery, Conn
Do While Not (Rs.BOF Or Rs.EOF)
Debug.Print Rs.Fields("DAV:displayname")
Rs.MoveNext
Loop
同様に、特定のプライベート フォルダにあるドキュメントや、既定のパブリック フォルダ階層以外の階層にあるドキュメントだけを探索したい場合は、次のように深いトラバースを使用できます。
strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""
strQuery = strQuery & " FROM SCOPE('deep traversal of """ & URL & """')"
strQuery = strQuery & " WHERE ""DAV:isfolder"" = False AND "
strQuery = strQuery & """DAV:ishidden"" = False AND "
strQuery = strQuery & """DAV:contentclass"" = 'urn:content-classes:document'"
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open strQuery, Conn
Do While Not (Rs.BOF Or Rs.EOF)
Debug.Print Rs.Fields("DAV:displayname")
Rs.MoveNext
Loop
コンテンツ管理
項目の作成
次の例では、TestFolder という名前の新しいパブリック フォルダを作成しています。この名前のフォルダがすでに存在していないことを仮定しています。
'Reference MS ADO 2.5 Library
strUrl = "http://myserver/public"
Set Conn = CreateObject("ADODB.Connection")
Conn.Provider = "ExOLEDB.DataSource"
Conn.Open strUrl
Set Rec = CreateObject("ADODB.Record")
Rec.Open strUrl & "/TestFolder", Conn, adModeReadWrite, adCreateCollection
ADO 2.5 Library のadCreateCollection定数がフォルダの作成を指示します。DAV:isfolder (=True) や DAV:contentclass (="urn:content-classes:folder") といった適切なプロパティは必要に応じて設定されます。
次の例では、パブリック フォルダ TestFolder に新しいメッセージ項目を作成しています。
strUrl = "http://myserver/public/TestFolder"
Set Conn = CreateObject("ADODB.Connection")
Conn.Provider = "ExOLEDB.DataSource"
Conn.Open strUrl
Set Rec = CreateObject("ADODB.Record")
Rec.Open strUrl & "/test.EML", Conn, adModeReadWrite, adCreateNonCollection
ADO 2.5 Library の adCreateNonCollection 定数がメッセージ項目の作成を指示します。Record オブジェクトの Field コレクションを使用して、作成した項目のスキーマに応じてプロパティ値を更新できます。次の例のようにカスタム フィールドを追加することもできます。
Rec.Fields("DAV:displayname") = "no longer a test"
Rec.Fields("test") = "This is a test"
Rec.Fields.Update
この例ではDAV:displaynameプロパティを更新して、カスタム プロパティ「test」を Field コレクションに追加しています。
項目の変更
次の例では、レコードセット全体をループ処理することによってフォルダ内の項目のフィールドを更新する方法を示します。
Set Rs = CreateObject("ADODB.Recordset")
Set Rec = CreateObject("ADODB.Record")
i = 1
Do While Not (Rs.BOF Or Rs.EOF)
Rec.Open Rs
With Rec.Fields("urn:schemas:httpmail:subject")
.Value = .Value & " - " & i
Rec.Fields.Update
End With
Rs.MoveNext
Rec.Close
i = i + 1
Loop
コンテンツの検索
クエリの作成
Web Storage System の検索は、Microsoft Distributed Authoring Search Language (MS-DASL)の仕様に従って実行され、DAV:sql という SQL クエリ文法を使用して実装されます。これらの SQL クエリは、Web Storage System プロパティ情報の ADORecordオブジェクトか ADORecordsetオブジェクトを返します。HTTP/1.1 または Distributed Authoring and Versioning (WebDAV)は、検索を実行するために SQL クエリを XML 要素と XML メソッドに変換します。
SELECT ステートメント
SELECTステートメントを使用して、データ ストア内の 1 つまたは複数のフォルダ内の項目について、プロパティ値を返すことができます。SELECT ステートメントの構文は次の通りです。
SELECT * | 選択リスト
FROM SCOPE(リソース リスト)
[WHERE 検索条件 ]
[order-by 句 ]
特定のプロパティをリクエストするには、次の例のように各プロパティ名を二重引用符で囲み、カンマで区切ります。
SELECT "DAV:href", "DAV:displayname" ...
クエリの範囲の定義
リレーショナル SQL ステートメントの場合と同じく、FROM 句を使用して検索の範囲を指定できます。リレーショナルデータベースのテーブルのクエリとは異なり、Web Storage System ではフォルダの URL と深さによって指定したフォルダの範囲を対象にクエリを発行します。
深い検索と浅い検索を使用した検索範囲の指定
検索範囲は SQL 要素 SCOPE を使用して定義します。SCOPE 要素内部では、検索するフォルダの深さと URL を定義します。指定フォルダ内だけを検索する場合は浅い検索を指定でき、あるフォルダとその下のすべてのサブフォルダを検索する場合は深い検索を指定できます。浅い検索には 'shallow traversal of' を指定し、深い検索には 'deep traversal of' を指定します。深さを指定したあとで、フォルダごとに URL を指定します。このステートメントの構文は次のいずれかになります。
SCOPE('shallow traversal of "URL1"', ['shallow traversal of "URL2"'])
または
SCOPE('deep traversal of "URL1"', ['deep traversal of "URL2"'])
たとえばあるフォルダのすぐ下のサブフォルダを検索するには、次の SQL ステートメントを実行します。
SELECT ""DAV:href"", ""DAV:displayname""
FROM SCOPE('shallow traversal of "URL"')
WHERE ""DAV:isfolder"" = True and ""DAV:ishidden"" = False
浅いトラバースなので、サブフォルダの内容は検索対象に含まれません。検索範囲を広げてすべてのサブフォルダを検索対象にするには、次の SQL ステートメントを実行します。
SELECT ""DAV:href"", ""DAV:displayname""
FROM SCOPE('shallow traversal of "URL"')
WHERE ""DAV:isfolder"" = True and ""DAV:ishidden"" = False
WHERE 句
SQL クエリの中で WHERE キーワードを使用して、取得するレコードが満たさなければならない条件句を作成できます。条件を連結するには AND キーワードと OR キーワードを使用します。複数の条件を 1 つの論理条件にグループ化するには括弧を使用します。構文は次の通りです。
WHERE 条件
結果が最終的に TRUE か FALSE であれば、条件はただ 1 つの論理条件であっても、論理条件のセットであっても構いません。
WHERE句の中では、以下を含む複数の述語を使用できます。
- LIKE
- FORMSOF
- CONTAINS
- ORDER BY
- FREETEXT
- GROUP BY
LIKE、CONTAINS、FREETEXT は、対象データ ストアに対する内容のインデックス生成が有効になっている場合に限り使用できます。
LIKE を使用した文字のマッチング
一般的な WHERE 句条件の一部に述語 LIKE を使用して、文字のマッチングを実行できます。LIKE は指定されたプロパティの値と指定された文字群を、次の例のように 1 文字ずつ比較します。
WHERE "urn:schemas:httpmail:sendername" LIKE "Jones"
CONTAINS を使用した単語のマッチング
述語 CONTAINS は、指定された単語と語句に正確に一致するものを検索します。次の例では、特定の差出人から、指定された語句を含むすべてのメッセージを検索します。Conn が有効な Connection オブジェクトで、strURL が有効なフォルダ URL であることを前提としています。
strQuery = "SELECT ""DAV:displayname"""
strQuery = strQuery & " FROM """ & strURL & """"
strQuery = strQuery & " WHERE CONTAINS(*, ' ""some phrase"" ')"
strQuery = strQuery & " AND CONTAINS(""urn:schemas:httpmail:sendername"","
strQuery = strQuery & " ' ""userx"" ')"
Rs.Open strQuery, Conn
FREETEXT を使用した単語のマッチング
より広範囲の検索については、WHERE 句の一部に述語 FREETEXT を使用できます。FREETEXT は、指定された 1 つ以上の語にあいまいに一致する任意の項目を検索します。たとえば次のクエリでは、Columbia、Seattle、Montreal のいずれかを含む任意の項目を検索します(大文字と子文字が区別されません)。
strQuery = "SELECT ""DAV:displayname"""
strQuery = strQuery & " FROM """ & strURL & """"
strQuery = strQuery & " WHERE FREETEXT(*, ' ""Columbia Seattle Montreal"" ')"
Rs.Open strQuery, Conn
FORMSOF を使用した語尾の異なる語の検索
WHERE句の一部に述語 FORMSOF を使用して、「expect」、「expecting」、「expectation」のような語尾の変化を検索できます。FORMSOF は次の例のように、通常は CONTAINS か FREETEXT 述語と組み合わせて使用します。
strQuery = "SELECT ""DAV:displayname"" FROM """ & strURL & """"
strQuery = strQuery & " WHERE CONTAINS('FORMSOF(INFLECTIONAL,""expect"") ')"
Rs.Open strQuery, Conn
ORDER BY を使用したクエリ結果の並べ替え
ORDER BY句によって、返されるレコードセットを、指定した 1 つ以上のプロパティを基準に昇順か降順に並べ替えることができます。次の例では特定の差出人からのすべてのメッセージを検索して、受信した日付を基準に昇順で並べ替えます。
strQuery = "SELECT ""DAV:displayname"",""urn:schemas:httpmail:datereceived"""
strQuery = strQuery & ", ""urn:schemas:httpmail:sendername"" FROM "
strQuery = strQuery & """" & strURL & """ WHERE " & _
"CONTAINS(""urn:schemas:httpmail:sendername"", ' ""Userx"" ') "
strQuery = strQuery & "ORDER BY ""urn:schemas:httpmail:datereceived"" ASC"
Rs.Open strQuery, Conn
GROUP BY を使用した項目数の取得
述語 GROUP BY は、返されるレコードセットを、SELECT ステートメントで指定した 1 つまたは複数のプロパティを基準にグループ化します。
次の例では、添付ファイルがあるメッセージとないメッセージの数のそれぞれの合計を求めます。
strQuery = "SELECT ""DAV:visiblecount"", ""urn:schemas:httpmail:importance"""
strQuery = strQuery & " FROM """ & strURL & """ GROUP BY"
strQuery = strQuery & " ""urn:schemas:httpmail:importance"""
Rs.Open strQuery, Conn
GROUP BY を使用するとき、SELECT ステートメントにDAV:visiblecount プロパティを指定することによって、返されるレコードセット内の各グループの出現回数を返すことができます。
トランザクションの使用
多くの場合クエリは大きなデータセットを対象とし、通常は何回もデータ ストアを呼び出す必要があります。Web Storage System 内の項目を対象にクエリや更新を行うとき、複数のデータ リクエストを 1 つのグループにまとめて、トランザクション、つまりグループ化された操作として実行することができます。これは「すべてかゼロか」という条件を適用したい場合にも有効です。たとえば互いに依存し合う 2 つの項目を作成したいとき、最初の項目を作成する試みが失敗した場合は 2 つ目の項目の作成をキャンセルするといったことができます。
Connectionオブジェクトに、グループ操作を容易にする次の 3 つの ADO メソッドがあります。
- BeginTrans。新しいトランザクションを開始します。
- CommitTrans。現在のトランザクションの間に実行されたあらゆる変更を保存した上で、現在のトランザクションを終了します。
- RollbackTrans。現在のトランザクションの間に実行されたあらゆる変更をキャンセルした上で、現在のトランザクションを終了します。
次の例は、フォルダ内の項目 1 つ 1 つのSubjectフィールドを更新します。
Sub Main()
Set Rs = CreateObject("ADODB.Recordset")
Conn.BeginTrans
Set Rec = CreateObject("ADODB.Record")
Do While Not (Rs.BOF Or Rs.EOF)
Rec.Open Rs
With Rec.Fields("urn:schemas:httpmail:subject")
If .Value = "test" Then
Conn.RollbackTrans
Rec.Close
Rs.Close
Conn.Close
Debug.Print "Transaction Rolled Back"
Exit Sub
End If
Debug.Print "BEFORE UPDATE: " & .Value
.Value = .Value & " - updated by transaction"
Rec.Fields.Update
Debug.Print "AFTER UPDATE: " & .Value
End With
Rs.MoveNext
Rec.Close
Loop
Conn.CommitTrans
End Sub
いずれかの項目の Subject が「test」に等しければ、グループ操作全体がキャンセルされます。Microsoft Visual Basic(R) のイミディエイト ウィンドウを使用して Debug.Print コマンドの出力を観察すれば、Subject フィールドの値が、操作の発生と同時に新しい値で更新されるように見えることに気がつくでしょう。ただし更新は実際にはデータのコピーに対して実行されています。データ ストアに対する変更が CommitTrans メソッドを使用してコミットされなかった場合、変更はキャンセルされ、データ ストア内のデータは更新されません。グループ操作の前、進行中、後の項目を Microsoft Outlook か Internet Explorer を使用して観察すれば、この動作を確認できます。
注意
Exchange 2000 Server 用の OLE DB プロバイダは、トランザクションのネストには対応していません。そのために別のトランザクションの実行中はトランザクションを開始できません。また、トランザクションのネスト レベルを示す「level」の戻り値は適用されません。OLE DB プロバイダはトランザクションの完全な分離は実現しませんが、コミット済み読み取り(カーソル内で安定)レベルの分離はサポートします。
接続は Web Storage System 内の単一のストアに対応付けられるため、複数のデータ ストアにまたがるグループ操作は実行できません。
SELECT *
Exchange 2000 では大量のプロパティを問い合わせることができるため、絶対に必要というのでなければクエリ内での SELECT * の使用は避けてください。SELECT * を使用すると、指定したコレクションのスキーマによって定義されているすべてのプロパティ(あるいはカラム)のレコードセットが作成されます。この広範囲のレコードセットの構築に必要なサーバー処理は、すべてのカラムを使用するのでない限り無駄になります。したがって、クエリ文字列には、SELECT * ではなく、処理の対象となるカラムだけを指定するようにしましょう。
複数データ ストアの検索
SELECTコマンドは OLE DB セッション(ADO 接続)内で実行されるため、検索対象ストア(パブリックまたはメール ボックスの)とフォルダ ツリーは暗黙のうちに定義されます。このため複数のデータ ストアにまたがる検索を、1 つの SQL コマンドを使用して実行することはできません。
MAPI フォルダ ツリー
Microsoft Exchange 2000 Server が MAPI クライアント用にインストールするパブリック データ ストアでは、単一フォルダの浅い検索だけがサポートされます。ただしプライベート データ ストアとその他のあらゆるパブリック フォルダ階層については、深い検索を実行できます。
深い検索と浅い検索の使用
SCOPE 要素に複数のフォルダを指定するときは、フォルダごとに同じ深さを使用しなければなりません。1 つの SQL コマンド内では、深い検索と浅い検索を併用することはできません。
おわりに
ADO 2.5 と OLE DB は、馴染みのある方法で Exchange データ ストアにアクセスする手段を提供します。Exchange 2000 Server がリリースされる前は、馴染みのない方法で Exchange データにアクセスしなければなりませんでした。今後は、従来型のデータ ストアにアクセスするのに使っていたのと同じ方法で、Web Storage System の階層データにアクセスできます。
詳細について
詳細については下記を参照してください。