次の方法で共有


Microsoft SQL Server 2005 の XML オプション

 

Microsoft Corporation

January 2005

対象 :
   Microsoft SQL Server 2005
   Microsoft Visual Studio 2005
   Microsoft .NET Framework 2.0
   XML とリレーショナル データ

概要 : Visual Studio 2005 環境や SQL Server 2005 環境で XML データを扱うための 3 つのオプションについて説明します。また、オプションを選択する場合に役立つ使用シナリオやガイドラインについても触れます。

目次

System.Xml、SQLXML、XML データ型の紹介
XML の使用シナリオ
.NET Framework の XML クラス
SQLXML
リレーショナルと XML の統合のサーバー側サポート (FOR XML と OPENXML)
SQL Server 2005 の XML データ型
さまざまなアプローチの比較
まとめ
関連情報

System.Xml、SQLXML、XML データ型の紹介

ここでは、Microsoft SQL Server 2000 で導入された XML サポートを簡単に振り返り、XML データとリレーショナル データを操作するために Microsoft Visual Studio 2005 環境や SQL Server 2005 環境で提供される 3 つのオプションを概説します。 この 3 つのオプションとは、1) System.Xml 名前空間のクラス、2) SQLXML クラス、3) SQL Server 2005 で提供される XML データ型のことです。

ユーザーに以下の機能を提供するために Microsoft SQL Server 2000 に XML サポートが追加されました。

  • リレーショナル データを XML として公開する
  • XML ドキュメントを行セットに細分する
  • XML-Data Reduced (XDR) スキーマを使用して XML スキーマをデータベース スキーマにマップすることで、XML ビューを作成する
  • XPath を使用して XML ビューでクエリを作成する
  • HTTP 経由で SQL Server のデータを公開する

このサポートは、それ以降の SQLXML Web リリースでさらに強化されました。 強化された機能には以下のものがあります。

  • XML ビューへの変更を保存するためのアップデートグラムと XML Bulkload
  • マッピングを記述するための注釈付き XML スキーマ定義言語 (XSD) のサポート (XDR は依然としてサポートされていますが、お勧めしません)
  • クライアント側の FOR XML
  • SQLXML マネージ クラス
  • Web サービスのサポート

Microsoft .NET Framework 1.0 では、XML ドキュメントの読み取り、書き込み、および処理が幅広くサポートされます。 このサポートは .NET Framework 2.0 でさらに強化され、さまざまな XML クラスのパフォーマンスと利便性が向上しました。 .NET Framework で提供される System.Xml 名前空間の新しいクラスは、リレーショナル データへの XML データのマッピングおよびリレーショナル データからの XML データのマッピングに使用できます。

SQLXML は、SQL Server データベースに保存されているリレーショナル データと XML をシームレスに統合できる一連のライブラリおよびテクノロジです。 SQLXML は中間層コンポーネントで、FOR XML や OPENXML によって提供されるサーバー側の XML サポートを含みません。 SQLXML には、リレーショナル ソース データから XML を生成し、リレーショナル情報を表す XML をリレーショナル テーブルに再度読み込むためのスキーマ ドリブン マッピング アプローチが用意されています。 SQLXML クラスによって、SQL Server 2000 以降のデータベースに XML サポートが提供されます。

Microsoft SQL Server 2005 には、XML に対する組み込みのサポートが XML データ型の形式で追加されています。 XML データは、ネイティブに XML データ型の列に格納できます。 また、XML データ型の列は、XML スキーマ コレクションと関連付けることでさらに制約できます。 XML データ型の列に格納した XML 値は、XQuery および XML Data Modification Language (DML) を利用して操作できます。 XML データにインデックスを設定して、クエリのパフォーマンスを向上させることができます。 さらに、FOR XML と OPENXML が、新しい XML データ型をサポートするように機能強化されました。

SQL Server 2005 に導入された XML データを格納および処理するための新機能と、前バージョンの SQL Server で提供された XML 機能が一体となって、XML データを XML アプリケーションで格納および処理できる方法が開発者に提供されます。 SQL Server 2005 には XML アプリケーションを構築できる複数のアプローチが用意されているので、適切なアプローチを選択するために、さまざまなテクノロジのシナリオ、トレードオフ、シナジーを理解しておくことが重要になります。 この資料では、SQL Server 2005 を使用する XML アプリケーションの開発で適切なアプローチを選択するためのガイダンスを提供します。

XML 使用シナリオ

XML を使用する分野は、大別すると以下のようになります。

  • ビジネスを統合するための XML: A2A (アプリケーション間)、B2B (ビジネス間)、B2C (企業 - 消費者間) の各アプリケーションなど、エンタープライズ アプリケーション統合 (EAI) とも呼ばれるビジネス統合。 異種システムで機能するアプリケーション間では、XML ベースのメッセージを使用して相互に通信が行われます。
  • コンテンツを管理するための XML: ユーザーは、XML に基づくコンテンツ管理システムにより、XML ドキュメントの格納、取得、変更、照会を行うことができます。 このようなシステムでは、システムのネイティブ形式で XML ドキュメントが格納されます。

次に、前述のカテゴリに分類されるいくつかのシナリオについて説明します。 ここで説明するシナリオのソリューションについては、SQL Server 2005 環境や Visual Studio 2005 環境で使用できるさまざまな XML オプションを詳しく説明しながら、後続のセクションで説明します。

シナリオ 1: 保険金請求

インターネット上でサービスを提供している自動車保険会社では、保険購入者や保険代理店が、この保険会社の Web サイト経由で保険金を請求できるようにしています。 このような請求は、保険会社の本社にある集中管理されたシステムで処理されます。 システムでは、処理が完了した後、請求に関連する特定の情報を、指定された XML 形式で格納する必要があります。 法律上の理由から、これらの XML ドキュメントの正確なコピーをシステムで管理しておく必要があります。 このシナリオは、コンテンツを管理するために XML を使用する例です。

シナリオ 2: 自動車メーカーと自動車部品販売業者間でのデータ交換 1

自動車メーカーは、複数の自動車部品販売業者から必要な部品の納入を受けています。 現在のところ、このメーカーでは、業者から請求書を受け取っています。 請求書を受け取ると、これらの請求書に記載されているデータを、従来からの請求書処理システムに手入力しています。 請求書処理システムでは、データがリレーショナル形式で格納されます。 現在、メーカーでは、従来からの請求書処理システムへの請求書データの入力処理を自動化したいと考えています。 このシナリオは、ビジネスを統合するために XML を使用する例です。

シナリオ 3: 自動車メーカーと自動車部品販売業者間でのデータ交換 2

このシナリオは、前述のシナリオで説明した、複数の自動車部品販売業者から部品の納入を受ける自動車メーカーの例です。 このメーカーの現システムには、業者が請求書の状態を確認したり、支払い指図書のコピーをメーカーから入手するための機能が備わっていません。 現在、業者は、これらの情報を電話でしか入手できません。 メーカーは、業者がこのような作業を自動的に実行できるように、情報を Web 上に公開できるようにする必要があります。 このシナリオは、ビジネスを統合するために XML を使用する例です。

シナリオ 4: コンテンツ管理システム

ある企業では、Web、書籍、CD-ROM などのさまざまな媒体を使って、医療、法律、テクノロジなどの各分野の情報を顧客に提供しています。 同社では、コンテンツ管理システムを構築して、高品質なコンテンツをより短時間で顧客に配信できるようにしたいと考えています。 このシナリオは、コンテンツを管理するために XML を使用する例です。

シナリオ 5: 顧客アンケート

ある企業では、インターネット上での航空券予約サービスを提供し、シーズンごとに調査を実施して、そのシーズンで顧客に最も人気のあった旅行先を特定しています。 使用するアンケート用紙はシーズンごとに異なり、今後もアンケート用紙を変更していく可能性があります。 同社では収集した情報を分析し、その分析結果を使用して、最も多くの顧客のニーズを満たすパッケージ旅行を計画しています。 このシナリオは、コンテンツを管理するために XML を使用する例です。

.NET Framework の XML クラス

Microsoft .NET Framework には、XML ベースの製品開発に対する優れたサポートが用意されています。 .NET Framework では、XmlTextReaderXmlTextWriterXmlDocumentXmlValidatingReader などのコア クアラスを System.Xml 名前空間で使用できます。System.Xml 名前空間は、すべての XML クラスのルート名前空間です。 ユーザーは、これらのコア クラスにより、ストリーム ベースや DOM ベース (ドキュメント オブジェクト モデル ベース) の両方のナビゲーション モデルとアクセス モデルを使用して、XML ドキュメントの読み取り、書き込み、検証を行うことができます。 System.Xml 名前空間には、以下の副名前空間が含まれています。

  • System.Xml.Schema – XML スキーマ定義言語 (XSD) スキーマを処理するためのクラスを含みます。
  • System.Xml.Serialization – XML 形式のドキュメントまたはストリームにオブジェクトをシリアル化するためのクラスを提供します。
  • System.Xml.XPath – XPath 式を使用して XML ドキュメント間を移動するためのクラスを含みます。
  • System.Xml.Xsl – Extensible Stylesheet Language Transformations (XSLT) を実行するためのクラスを含みます。

System.Xml 名前空間の機能強化

Visual Studio 2005 では、XsltCommand などの新しいクラスおよび XmlDocument などの既存の XML クラスに対する機能強化を使用して、XML ドキュメントの変更や XSL 変換の適用など、XML データ上でさまざまな操作を実行できます。

System.Xml 名前空間の XML クラスに関する Visual Studio 2005 での機能強化には、以下のものがあります。

  • XML スキーマ検証のサポートが、XmlDocument クラスに追加されました。
  • パフォーマンスを大幅に向上させ、XML スキーマ型をサポートするために、XmlReader クラスと XmlWriter クラスの機能が強化されました。 また、作成した型を構成するために XmlReaderSettings クラスおよび XmlWriterSettings クラスを使用して XmlReaderXmlWriter のインスタンスを容易に作成できるように、静的な Create メソッドが追加されました。

System.Xml の機能強化の詳細については、「What's New in System.Xml for Visual Studio 2005 and the .NET Framework 2.0 Release」 (英語) を参照してください。

System.Xml 名前空間のクラスを使用して、独自の XML 解析、操作、およびストレージに関するロジックを実装できます。 SQL Server 2005 の共通言語ランタイム (CLR) ホスト機能、および Visual Studio 2005 の XML クラスを使用すると、中間層またはデータベース層のいずれかで XML 処理を実行できます。

.NET Framework の XML クラスを使用するには、XML ドキュメントを [n]varchar(max) 型または varbinary(max) 型の列としてデータベースに格納するか、ファイルとしてファイル システムに格納し、System.Xml 名前空間のクラスを使用して、中間層またはデータベースでこれらのドキュメントを処理する必要があります。 また、.NET Framework の XML クラスを使用して、XML データ型に格納されたデータを操作することもできます。

以下の場合、.NET Framework の XML クラスを選択することが適しています。

  • ストリーム パーサー、文書型定義 (DTD) と XSD の検証、XSLT 処理など、すべての .NET Framework XML 機能にアクセスできるようにする場合。
  • SQL Server を単に XML ドキュメントのデータ ストアとして使用し、データベースの内部できめ細かいアクセスが不要な場合。
  • XML ドキュメントでの大部分またはすべての処理を .NET Framework の XML クラスを使用して行い、ドキュメント レベルで更新を実行する場合。

XML を格納するには、[n]varchar(max)varbinary(max)、または XML データ型を使用できます。

[n]varchar(max) または varbinary(max) を使用すると、以下のメリットが得られます。

  • 空白や書式設定を含めた XML ドキュメントの正確なコピーにより、そのドキュメントのテキストの再現性が確保されます。
  • ドキュメント全体で挿入操作や取得操作を行うことで、アプリケーションのパフォーマンスが最大限に引き出されます。

XML データ型を使用するメリットについては、後半のセクションで説明します。

中間層での XML 処理の実行

XML 処理は、.NET Framework に備わっているさまざまな XML クラスを使用して中間層で実行できます。 前述のように、このアプローチを採用すると、XML ドキュメントを [n]varchar(max) 型の列または XML としてデータベースに格納するか、ファイルとしてファイル システムに格納できます。 中間層では、これらのドキュメントをデータベースから取得し、以下のようにユーザーの要件に応じて処理します。

  • XML ドキュメントを読み込む必要がある場合は、XmlReader.Create() メソッドで作成した XmlReader を使用して、データベースから取得したドキュメントを読み込みます。 Read() を使用してドキュメント内を移動します。 XmlReader クラスにより、読み取り専用、前方のみ、かつキャッシュを使用しない、XML ドキュメントへの可能な限り高速なアクセスが提供されます。
  • XML ドキュメントへの書き込みアクセス権、および XML データへの完全なナビゲーション アクセス権が必要な場合は、XmlDocument クラスを使用して XML ドキュメントを読み込み、そのドキュメントにアクセスします。 XmlDocument は .NET Framework のドキュメント オブジェクト モデル (DOM) の実装です。これにより、XML ドキュメントがインメモリ ツリーとして表現されるので、このドキュメントのナビゲーションや編集が可能になります。
  • DTD や XSD に基づいて XML ドキュメントを検証する必要がある場合、または実行時に XSD 情報を取得する必要がある場合は、XmlReader クラスを使用します。 XsdValidation または DTDValidation のいずれかに True を設定して、XmlReaderSettings クラスでメソッドを作成します。 また、読み取り中に発生した検証エラーを処理するために、ValidationEventHandle() イベント ハンドラを設定することもできます。
  • XML ドキュメントに XSL 変換を適用する必要がある場合は、XPathDocument クラスを使用して XML ドキュメントを読み込み、XslCommand クラスを使用して変換を適用します。 XPathDocument クラスにより、XSLT を使用して XML ドキュメントを処理するための、高速かつパフォーマンスの高いキャッシュが提供されます。
  • XPath 式を使用して XML ドキュメントにクエリする必要がある場合は、XPathDocument (読み取り専用) または XmlDocument (読み取りおよび書き込み) のいずれかを使用して、XML ドキュメントを読み込みます。 CreateNavigator() メソッドを使用して XPathNavigator のインスタンスを作成し、必要な XPath 式を引数として XPathNavigatorSelect() メソッドに渡します。

データベースでの XML 処理の実行

SQL Server 2005 の CLR との統合により、開発者は .NET Framework に備わっている XML クラスを使用して、データベース層でも処理を実行できます。 この統合により、ストアド プロシージャ、関数、トリガ、およびユーザー定義型を .NET Framework でサポートされているすべての言語で記述できます。 さらに、CLR ホストにより、完全な .NET Framework 基本クラス ライブラリにアクセスすることもできます。 したがって、前のセクションで説明したさまざまな XML 処理オプションをデータベースで実行することもできます。

CLR 統合を使用するメリットは、以下のとおりです。

  • データベース オブジェクトをマネージ コードで作成するために、C# や Visual Basic .NET などのオブジェクト指向言語を使用できます。
  • マネージ データベース オブジェクトは、前バージョンの SQL Server で使用できた拡張ストアド プロシージャよりもセキュリティが強化されています。
  • ユーザー定義データ型やユーザー定義集計を定義できます。
  • 特定の環境では、コンパイル済みのマネージ データベース オブジェクトにより、Transact-SQL を上回る優れたパフォーマンスが提供されます。

SQL Server 2005 には、データベース開発者がストアド プロシージャ、トリガ、およびユーザー定義関数を記述するための選択肢が 2 つあります。 1 つは Transact-SQL で、もう 1 つは C# や Visual Basic .NET など、.NET Framework で使用できる任意の言語です。 どの言語を選択するかは、データで実行する操作の種類によって異なります。 Transact-SQL は、主に、手続き型のロジックをほとんど、またはまったく使わずに、コードからデータにアクセスする場合に最適です。 マネージ クラスは、算術演算を数多く実行する関数や、文字列の処理、データ操作、システム リソースへのアクセス、ファイルへのアクセス、画像の処理などのプロシージャを実行する場合に最適です。

以下に、データベース層で .NET Framework の XML クラスを使用するときに必要な手順を示します。

  • マネージ アセンブリを開発する。 .NET Framework で使用できる任意の言語を使用して、処理機能をアセンブリとして実装し、このアセンブリを DLL にパッケージ化します。 また、アセンブリから他のアセンブリを参照することもできます。
  • アセンブリを登録してアクセス許可の付与する。 .NET Framework を使用して開発したアセンブリは、CREATE ASSEMBLY T-SQL ステートメントを使用して SQL Server に登録できます。 アセンブリの登録時に、アセンブリに与えられるコード アクセス許可を指定することもできます。 アセンブリの登録は、DROP ASSEMBLY T-SQL ステートメントを使用して解除できます。
  • T-SQL にマネージ型を公開する。 アセンブリによって提供される処理機能は、スカラ値ユーザー定義関数、テーブル値ユーザー定義関数、ユーザー定義プロシージャ (UDP)、またはユーザー定義トリガを使用して T-SQL に公開できます。 スカラ ユーザー定義関数は、任意のスカラ式で使用できます。 テーブル値ユーザー定義関数は、任意の FROM 句で使用できます。 UDP は、EXEC ステートメントで呼び出すことができます。

シナリオの分析

保険金請求には、請求 ID、ポリシー番号、保険金支払いデータなどのデータ中心の情報と、事故損害の説明などのドキュメント中心の情報が含まれます。 XML ドキュメントは、データ中心の情報とドキュメント中心の情報を集約するのに優れています。 現在のシナリオ (「シナリオ 1: 保険金請求」を参照) の重要な要件は、保険金請求の正確なコピーを XML 形式で保持するニーズです。 SQL Server の場合、保険金請求を [n]varchar(max) 型または varbinary(max) 型の列としてデータベースに格納することで、この要件を容易に満たすことができます。 意味のない空白、属性の順序、名前空間プレフィックス、XML 宣言などの情報を保持する必要がある場合は、ドキュメントの格納に XML データ型を使用できないことに注意することが重要です。

メリット

[n]varchar(max) または varbinary(max) を保存媒体として使用し、XML ドキュメントの操作で System.Xml 名前空間のクラスを使用すると、以下のメリットが得られます。

  • XML ドキュメントのスキーマを変更する必要があるときに、柔軟性があります。 また、XML ドキュメントを異なるスキーマを使用して同じ列に格納するときに便利です。
  • [n]varchar(max) または varbinary(max) を使用して XML を格納すると、XML ドキュメントのテキストの再現性が確保されます。 このことは、保険金請求などの法務文書を処理するアプリケーションでは、必要条件になることがあります。
  • XML インスタンスをファイルとしてファイル システムに格納する場合と比べると、トランザクション更新、同時アクセス、バックアップ、レプリケーションなどのデータベース機能を活用できます。
  • このアプローチは、データベースによって提供される XML サポートに依存しないので、SQL Server や Oracle などの複数のデータベース サーバーをサポートするように、アプリケーションを容易に拡張できます。
  • クライアント システムの処理能力を使用できるので、サーバーの負荷が下がります。 CPU を集中的に使用する XML 処理を中間層で実行すると、サーバーの負荷がいくぶん下がり、他の重要なタスクがサーバーを使用できます。
  • ドキュメント レベルの挿入操作と取得操作で、可能な限り最適なパフォーマンスが提供されます。
  • XSL 変換などの複雑な操作を、ストアド プロシージャ、トリガ、関数としてデータベースで実行できます。

制限事項

格納に [n]varchar(max) または varbinary(max) を使用し、XML インスタンスの処理に System.Xml 名前空間のクラスを使用する場合の制限事項は、以下のようにまとめることができます。

  • XML データ型 (「SQL Server 2005 の XML データ型」を参照)、または SQLXML オプション (「SQLXML」を参照) と比較して、コーディングが複雑になります。 データベース ロジックが単純な場合でも、中間層やデータベース層で XML の解析や処理を行うコードの実装が複雑になります。
  • このソリューションを実装するには、大量のコードが必要です。 したがって、SQLXML オプションに比べて管理コストも高くなります。
  • XML ドキュメントが [n]varchar(max) としてデータベースに格納されるので、XML ドキュメントできめ細かい更新、挿入、または削除操作を実行できません。 クエリ機能が制限されます。
  • [n]varchar (max) データ型に格納できる XML ドキュメントのサイズが、2 GB に制限されます。
  • XML コンテンツに基づいてこの方法で格納したドキュメントの列を検索するには、非常にコストが高くなります。

.NET Framework の XML クラスの使用例

この資料の前半で説明した保険金請求のシナリオ (「シナリオ 1: 保険金請求」を参照) について検討します。 保険会社では、請求が承認された後、法律上の理由から請求情報を格納することになります。 請求情報は、[n]varchar(max) データ型としてデータベースに格納できます。

このアプリケーションの流れは、以下のとおりです。

  1. 請求の処理後、アプリケーションによって請求が許可または却下されます。
  2. System.Xml 名前空間のクラスを使用して、請求の XML ドキュメントが生成されます。
  3. 生成された XML ドキュメントが、ストアド プロシージャに送信されます。
  4. ストアド プロシージャによって、XML ドキュメントがテーブルに挿入されます。

次のコードの例では、システムで入手できる請求の詳細情報を使用して XML ドキュメントを生成し、そのドキュメントをデータベースに挿入します。

using System;
using System.Xml;
using System.IO;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace InsuranceClaim
{
    class Insurance
    {
        static void Main(string[] args)
        {
            Insurance.InsertInsuranceClaim();
        }
        static void InsertInsuranceClaim()
        {
        StringWriter strWriter = null;
     XmlWriter writer = null;
 XmlWriterSettings settings = null;
     SqlConnection connection = null;
     SqlCommand command = null;
     try
     {
strWriter = new StringWriter();
settings = new XmlWriterSettings();
// 読みやすくするために、インデントを設定します。
      settings.Indent = true;
      settings.Encoding = System.Text.Encoding.UTF8;
      writer = XmlWriter.Create(strWriter, settings);
      // XML 宣言を書き込みます。 
      writer.WriteStartDocument();
      writer.WriteStartElement("InsuranceClaim");
      writer.WriteStartElement("ClaimInfo");
            writer.WriteElementString("ClaimID", "C1234");
            writer.WriteElementString("ClaimType", "3");
            writer.WriteStartElement("SettlementDetails");
            writer.WriteStartElement("PaymentDetails");
            writer.WriteElementString("PaidTo", "Jeff");
            writer.WriteElementString("Amount", "2000");
            writer.WriteElementString("Date", "05/12/2002");
            writer.WriteElementString("ApprovedBy", "Mike");
            writer.WriteEndElement();// PaymentDetails の最後
            writer.WriteEndElement();// SettlementDetails の最後
            writer.WriteEndElement();// ClaimInfo の最後
            writer.WriteStartElement("DamageReport");
writer.WriteString("Minor accident occured on ");
      writer.WriteElementString("Address", "ABC Street, Sample City, Sample State");
      writer.WriteString(" due to ");
      writer.WriteElementString("Cause", "bad weather");
      writer.WriteString(" resulted in damage to ");
      writer.WriteElementString("DamagedItem", "Head Lights");
      writer.WriteElementString("DamagedItem", "Engine");
            writer.WriteEndElement();// DamageReport の最後
            writer.WriteEndElement();// InsuranceClaim の最後
      writer.WriteEndDocument();
      // XML をファイルに書き込み、writer を閉じます。
      writer.Flush();
      connection = new SqlConnection();
      connection.ConnectionString = @"server=localhost;
      database=AdventureWorks;Integrated Security=SSPI;";
      command = connection.CreateCommand();
      command.CommandText = "InsertInsuranceClaim";
      command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.Add("@CustomerID", 
System.Data.SqlDbType.Char);
command.Parameters.Add("@Claim", 
System.Data.SqlDbType.VarChar);
      String xml = strWriter.ToString();
string strCustomerID = "1001";
            command.Parameters[0].Value = strCustomerID;
            command.Parameters[0].Size = strCustomerID.Length;
      command.Parameters[1].Value = xml;
      command.Parameters[1].Size = xml.Length;
      connection.Open();
      command.ExecuteNonQuery();
      connection.Close();
       }
       finally
       {
      if (connection.State == ConnectionState.Open)
         connection.Close();
      if (writer != null)
         writer.Close();
      if (strWriter != null)
         strWriter.Close();
       }
    }
    }
}

以下に、データベース テーブルを作成するスクリプトを示します。

CREATE TABLE [InsuranceClaim](
   [CustomerID] [char](4) NOT NULL,
   [Claim] [varchar](max) NOT NULL,
   [ModifiedDate] [datetime] NOT NULL DEFAULT (getdate())
)

次のストアド プロシージャを使用して、XML ドキュメントをデータベースに挿入します。

CREATE PROCEDURE [dbo].[InsertInsuranceClaim]
   @CustomerID [char](4),
   @Claim [varchar](max)
AS
BEGIN
       SET NOCOUNT ON;
   INSERT INTO [InsuranceClaim] ( CustomerID, Claim )
   VALUES ( @CustomerID, @Claim )
END;

SQLXML

SQL Server 2000 で導入された SQLXML には、クライアント側での XML 処理に関連するあらゆる種類の機能が含まれています。 SQLXML は、SQL Server データベースに保存されているリレーショナル データと、リレーショナルに構造化されたデータを記述する XML をシームレスに統合できる一連のライブラリおよびテクノロジです。

開発者は、SQL 2000 以前を使用していたころは、リレーショナル データと XML 形式のデータ間での相互作用を実現するために、コード層を実装する必要がありました。 SQLXML の登場により、リレーショナル データと XML 間のリンクが提供されたので、作業が容易になりました。 この資料で説明するトピックは、SQLXML マネージ クラスだけです。 ライブラリの他の機能の適用可能性の詳細については、MSDN の「SQLXML」 (英語) を参照してください。

SQLXML には、XML をサポートするために SQL Server に導入された多くの機能が含まれています。 以下に、これらの機能を示します。

  • クエリの結果をクライアント側の XML に変換する機能。
  • 注釈付き XSD マッピング スキーマ ファイルを使用して、リレーショナル データの XML ビューを作成する機能。この機能により、以下の操作を実行できます。
    • XML ビューに対する XPath クエリの定義。
    • アップデートグラムという XML テンプレートを使用した、データベース内のデータでの挿入、更新、または削除操作の実行。
    • XML 一括読み込み操作の実行。
  • HTTP を使用して SQL Server にアクセスする機能。この機能により、以下の操作を実行できます。
    • URL での SQL ステートメントの指定。
    • URL でのテンプレート クエリの指定。
    • URL でのテンプレート ファイルの指定。
    • URL での、注釈付き XSD マッピング スキーマ ファイルに対して記述された XPath クエリの指定。
  • ストアド プロシージャ、ユーザー定義関数、およびテンプレート クエリによって提供された機能を SOAP ベースの Web サービスとして公開する機能。
  • SQLXML マネージ クラスを使用して、SQLXML によって提供された XML 機能を利用するために .NET Framework のコードを記述する機能。

クライアント側の XML 書式設定。 クライアント側で FOR XML 句を指定すると、中間層により、クエリへの応答としてサーバーから返された行セットで FOR XML 変換が実行されます。 クライアント側で XML 書式を設定するには、以下のいずれかの操作を実行します。

  • SQLXML マネージ クラスを使用している場合は、SqlXmlCommand オブジェクトの ClientSideXml プロパティを TRUE に設定します。
  • SQLXMLOLEDB プロバイダを使用している場合は、ClientSideXML プロバイダ固有のプロパティを TRUE に設定します。
  • テンプレート クエリを使用している場合は、テンプレートで client-side-xml="1" と指定します。
  • HTTP を使用して SQL Server にアクセスしている場合は、[設定] タブで仮想ディレクトリの [クライアント上で実行] を選択します。
  • クライアント側の FOR XML で有効な XML 書式設定モードは、RAW、NESTED、および EXPLICIT です。 RAW モードを使用すると、結果として生成される XML ドキュメントに、クエリ結果の各行の XML 要素と、行の各列に対応する属性が 1 つずつ含まれます。 NESTED モードを指定すると、ベース テーブル名が、結果として生成される XML ドキュメントの要素名として返されます。 EXPLICIT モードでは、目的の XML の形式をクエリ自体に指定できるので、任意の形式の XML ドキュメントが生成されます。
  • **XML ビュー。**XML ビューは、リレーショナル データと XML データ間のマッピングを定義する注釈付き XSD スキーマを使用して作成します。 これらの XML ビューは、XPath クエリを使用してクエリできます。 また、XML ビューによって公開されたリレーショナル データを変更すると、その変更をアップデートグラムを使用してデータベースに送信できます。 さらに、XML ビューは、COM ベースの XML Bulk Load オブジェクトを利用して、データベースに膨大な XML ドキュメントを挿入する場合に役立ちます。
  • **SQL Server への HTTP アクセス。**SQLXML には、IIS 仮想ディレクトリ管理ユーティリティというユーティリティが用意されています。このユーティリティを使用すると、HTTP 経由で SQL Server の XML 機能を公開するように IIS 仮想ディレクトリを設定できます。 SQL ISAPI 拡張機能を使用することで、SQL ステートメント、ストアド プロシージャ、テンプレート クエリ、テンプレート ファイル、および XPath クエリを URL で直接指定できます。
  • **SQLXML での Web サービスのサポート。**SQL Server の機能を SOAP ベースの Web サービスとして公開するためのサポートは、SQLXML 3.0 で追加されました。 この機能により、SQL Server でクライアントから SOAP HTTP 要求を受信して、ストアド プロシージャ、ユーザー定義関数、およびテンプレートを実行できます。
  • SQLXML マネージ クラス。.NET Framework の SQLXML 機能には、SQLXML マネージ クラスを使用してアクセスできます。 SQLXML には、以下の 3 つのマネージ クラスがあります。
  • SqlXmlCommand - データベース接続とクエリ実行の側面を処理します。
  • SqlXmlParameter - クエリでパラメータを指定するのに役立ちます。
  • SqlXmlAdapter - .NET Framework のデータセットとの相互作用を容易にします。

SQLXML マネージ クラスにより、以下の操作を実行できます。

  • FOR XML 句を使用した SQL クエリの実行
  • マッピング スキーマに対する XPath クエリの実行
  • テンプレート クエリの実行
  • テンプレート クエリ ファイルの実行
  • アップデートグラムの実行
  • DiffGram の実行

以下の場合、SQLXML を使用してリレーショナル データを XML ドキュメントとして公開することが適しています。

  • アプリケーションにより、非常に構造化されていて、リレーショナル テーブルに適切にマップされる XML データが受信される場合。
  • アプリケーションによって、外部アプリケーションから受信した膨大な XML ドキュメントがデータベースに読み込まれ、そのドキュメントがリレーショナル形式で保持される必要がある場合。
  • アプリケーションに、ドキュメントの順序を保持するための要件がない場合。
  • アプリケーションによって、1 つのデータが複数のデータ コンシューマに異なる形式で提供される必要がある場合。
  • DML 操作のパフォーマンスが、アプリケーションにとって重要な場合。
  • アプリケーションに、クエリ最適化でオプティマイザの最大限の可能性を利用するための要件がある場合。
  • アプリケーションで、きめ細かいデータ操作が実行される場合。
  • アプリケーションによって、既存のリレーショナル データが XML として公開される必要がある場合。

シナリオの分析

XML 使用シナリオで説明した最初のデータ交換シナリオ (「シナリオ 2: 自動車メーカーと自動車部品販売業者間でのデータ交換 1」を参照) では、自動車メーカーと複数の自動車部品販売業者間での相互作用に、SQLXML を使用する典型的な例が示されます。 この自動車メーカーは、さまざまな自動車部品販売業者と連絡をとって、請求書データを交換する必要があります。 この問題の解決案では、Web サービスと SQLXML を使用します。 メーカーは、業者がメーカーに請求書を送信するために使用できる Web サービスを公開します。 Web サービスでは、顧客固有の XSLT を使用して、業者が使用する形式からメーカーが使用する共通形式に請求書が変換されます。 その後、Web サービスによって、請求書ドキュメントのコンテンツをリレーショナル テーブルの列にマップする XML ビューを使用して、XML ドキュメントが細分されます。 従来からの請求書処理システムでは、リレーショナル テーブルからデータを取得し、処理を続行できます。 このシナリオで XML ビューを使用するメリットは、以下のとおりです。

  • 低い保守コスト。 業者が行った請求書スキーマへのすべての変更には、業者固有の XSLT ファイルを変更することで容易に対応できます。
  • FOR XML (「リレーショナルと XML の統合のサーバー側サポート (FOR XML と OPENXML)」を参照) に比べて、コーディングが簡単です。
  • 業者固有の XSLT ファイルを作成することで、新しい業者を容易にサポートできます。

メリット

SQLXML を使用するメリットは、以下のようにまとめることができます。

  • リレーショナル データを XML データにマップする注釈付きマッピング スキーマを作成することは比較的簡単で、サーバー側の FOR XML EXPLICIT よりも管理しやすいソリューションです。
  • FOR XML を使用して作成するリレーショナル データの読み取り専用 XML 表記と比較して、SQLXML には、更新可能な双方向の XML ビューを作成する機能が備わっています。
  • マッピング XSD には、重要なコード変更を行わなくても、XML 形式の変更要求に対応する機能が用意されています。 そのため、管理しやすくなります。
  • SQLXML には、クライアント側で XML 書式を設定する機能が用意されています。これにより、ユーザーが SqlXMLCommand クラスの ClientSideXML プロパティを TRUE に設定できるので、サーバーの負荷が下がります。

制限事項

マイナス面として、SQLXML をクライアント側で使用するときに、以下のようないくつかの制限事項があります。

  • XML ビューは、XML ドキュメントの階層が深すぎるか、不明な深さまで再帰的になる場合は適していません。
  • SQLXML は、混合コンテンツ マークアップ、製品カタログやニュース レポートなど、順序付けられたデータを含む説明ドキュメントには適していません。
  • ドキュメントの順序が保持されないので、元の XML ドキュメントを再構築することが困難です。
  • XML ドキュメントをリレーショナル テーブルに分解すると、検索のパフォーマンスは向上しますが、XML への変換および XML からの変換にコストがかかります。
  • 既定のマッピングを XSD マッピング スキーマで使用すると、データベース テーブル名や列情報が公開されることがあります。このことは、意図しない情報の漏えいにつながることがあります。 このリスクは、テーブルと列に対して明示的なマッピングを指定することで回避できます。
  • URL の SQL ステートメントは、信頼されたイントラネットでしか使用できません。 そのようなクエリをインターネット上で使用すると、潜在的なセキュリティ上の問題を引き起こす可能性があります。

SQLXML の使用例

SQLXML の概要を完全に説明したので、次の手順として、SQLXML マネージ クラスを適用できる例を詳しく調べます。 特定の顧客の発注の詳細情報をエクスポートする単純な例について考えます。 この例で使用するテーブルは、AdventureWorks データベースから入手できます。

データベースから取得したデータは、クライアントで XML 形式で使用できる必要があります。このデータは、プレゼンテーション層で表示できます。 次に、SQL データベースのリレーショナル データを、SQLXML クラスを使用して XML データとして操作できる方法を確認します。 マッピング XML スキーマは、XML ノード名を操作し、テーブル フィールドにマップするために使用します。 SQLXML マネージ ライブラリを使用したリレーショナル データの操作の詳細については、MSDN の「SQLXML」 (英語) を参照してください。

次の注釈付き XSD スキーマでは、リレーショナル テーブル [Sales.Customer]、[Sales.SalesOrderHeader]、[Sales.SalesOrderDetail] と、顧客の発注の詳細情報の対象となる XML 表記間のマッピングを定義しています。 また、次の XSD スキーマで示すように、XML の親子リレーションシップを XSD マッピング スキーマを使用して定義することもできます。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
<xsd:annotation>
  <xsd:appinfo>
    <sql:relationship name="CustomerOrderHeader"
        parent="Sales.Customer"
        parent-key="CustomerID"
        child="Sales.SalesOrderHeader"
        child-key="CustomerID" />
    <sql:relationship name="OrderHeaderOrderDetail"
        parent="Sales.SalesOrderHeader"
        parent-key="SalesOrderID"
        child="Sales.SalesOrderDetail"
        child-key="SalesOrderID" />
  </xsd:appinfo>
</xsd:annotation>
  <xsd:element name="Customer" sql:relation="Sales.Customer" >
   <xsd:complexType>
     <xsd:sequence>
        <xsd:element name="Order" sql:relation="Sales.SalesOrderHeader"  
            sql:relationship="CustomerOrderHeader" maxOccurs="unbounded" >
          <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="OrderDetail" 
                             sql:relation="Sales.SalesOrderDetail" 
                             sql:relationship="OrderHeaderOrderDetail" 
                             maxOccurs="unbounded" >
                  <xsd:complexType>
                    <xsd:attribute name="SalesOrderID" 
type="xsd:integer" />
                    <xsd:attribute name="ProductID" type="xsd:integer" />
                    <xsd:attribute name="OrderQty" type="xsd:integer" />
                  </xsd:complexType>
                </xsd:element>
              </xsd:sequence>
              <xsd:attribute name="SalesOrderID" type="xsd:integer" />
              <xsd:attribute name="CustomerID" type="xsd:integer" />
              <xsd:attribute name="OrderDate" type="xsd:date" />
              <xsd:attribute name="ShipDate" type="xsd:date" />
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
      <xsd:attribute name="CustomerID" type="xsd:integer" />
     </xsd:complexType>
  </xsd:element>
</xsd:schema>
class ExportOrders
{
/// <summary>
///    This method use SqlXmlCommand class to select the records from 
///   Sales.Customer, Sales.SalesOrderHeader and Sales.SalesOrderDetail
///   tables.The data is fetched as such from server and formatted into
///   xml at client side. Note that the ClientSideXml is set to true.
/// </summary>
static void Main(string[] args)
{
   if (args.Length < 1)
   {
      Console.WriteLine("Usage");
      Console.WriteLine("CustomerOrders <CustomerID> [OrderID]");
      return;
   }

   try
   {
      StringBuilder strBuilder = new StringBuilder();
      strBuilder.Append("/Customer[@CustomerID='");
      strBuilder.Append(args[0]);
      strBuilder.Append("']");
      if (args.Length > 1)
      {
         strBuilder.Append("/Order[@SalesOrderID='");
         strBuilder.Append(args[1]);
         strBuilder.Append("']");
      }
SqlXmlCommand xmlCommand = new SqlXmlCommand(@"Provider=
SQLOLEDB; Server=localhost; database=AdventureWorks;
Integrated Security=SSPI;");
      xmlCommand.ClientSideXml   = true;
      xmlCommand.RootTag      = "CustomerOrders";
      xmlCommand.SchemaPath      = @"CustomerOrderDetails.xsd";
      xmlCommand.CommandType      = SqlXmlCommandType.XPath;
      xmlCommand.CommandText      = strBuilder.ToString();
      Stream reader         = xmlCommand.ExecuteStream( );
      FileStream fsOut = File.Create("CustomerOrder.xml");
      StreamWriter sw = new StreamWriter(fsOut);
      using (StreamReader sr = new StreamReader(reader))
      {
         sw.Write(sr.ReadToEnd());
      }
      sw.Flush();
      sw.Close();
      fsOut.Close();
   }
   catch (Exception exception)
   {
      Console.WriteLine( exception.ToString() );
   }
}
}

上記のメソッドにより、コマンド ライン引数として指定した顧客 ID の発注の詳細情報が、アプリケーションにエクスポートされます。 データは、クライアント側で XML 形式に変換されるので、サーバー側でパフォーマンスの問題が発生することを回避できます。 上記の注釈付き XSD スキーマ マッピングが正しく機能するには、上記のコード フラグメントを CustomerOrderDetails.xsd に保存する必要がある点に注意してください。

   上記の例を見てわかるように、データベースから XML としてデータを取得するコードは最少量に抑えられています。

リレーショナルと XML の統合のサーバー側サポート (FOR XML と OPENXML)

SQL Server では、SELECT ステートメントに対する FOR XML の機能強化を使用して、サーバー側で SQL クエリの結果を XML ドキュメントとして返すことができます。 また、OPENXML キーワードには、XML ドキュメントから行セットを取り出す機能が備わっています。

FOR XML

サーバー側の FOR XML では、RAW、AUTO、EXPLICIT、および PATH の 4 つの XML 変換モードがサポートされます。

既定では、RAW モードによって、クエリ結果セットの各行が XML 要素にマップされ、行の各列が属性にマップされます。 ROW モードで ELEMENTS オプションを指定すると、行の各列が、その行に対して生成される要素のサブ要素にマップされます。 また、XMLSCHEMA オプションを指定すると生成される XML のインライン スキーマを要求することもできます。

既定では、AUTO モードによって、入れ子になった XML 要素の生成がサポートされます。この場合、FROM 句の各テーブル (テーブルに対する列が、少なくとも 1 列 SELECT 句にリストされます) が XML 要素にマップされ、SELECT 句に表示される列が属性 (ELEMENTS オプションを指定している場合は、サブ要素) にマップされます。

EXPLICIT モードでは、クエリ結果から生成される XML の形式を最大限に制御できます。 これにより、目的の XML の形式をクエリ自体に指定することで、任意の形式で XML を生成できます。

EXPLICT モードを使用して複雑な XML ドキュメントを構成することは面倒です。 複雑な EXPLICIT モードのクエリを記述する代わりに、入れ子になった FOR XML クエリを記述する機能と XML 型のインスタンスを返す TYPE ディレクティブを併用する PATH モードを使用できます。 PATH モードでは、列名が XPath と同様の構文として解釈され、SELECT クエリから返された行セットの列が属性とサブ要素にマップされます。 SQL Server 2005 の FOR XML の機能強化の詳細については、「Microsoft SQL Server 2005 での FOR XML の新機能」を参照してください。

OPENXML

OPENXML と、sp_xml_preparedocument および sp_xml_removedocument システム ストアド プロシージャを一緒に使用すると、XML ドキュメントのリレーショナル行セット ビューが提供されます。 XML ドキュメントで OPENXML を使用するには、sp_xml_preparedocument を使用して、XML ドキュメントのインメモリ表現を作成する必要があります。 このストアド プロシージャにより、MSXML パーサーを使用して XML ドキュメントが解析され、OPENXML と共に使用できる XML ドキュメントへのハンドルが返されます。 現在は、XML ドキュメント ハンドル、rowpattern (XML データのノードを行にマップする XPath 式)、行セット スキーマ、行セット列と XML ノード間でのマッピングなどのパラメータを OPENXML に渡して、行セットを取得できるようになりました。 XML ドキュメントは不要になったら、sp_xml_removedocument ストアド プロシージャを使用してメモリからアンロードする必要があります。

FOR XML の機能強化

FOR XML は、SQL Server 2005 で以下の機能が強化されました。

  • 新しい TYPE ディレクティブを使用して FOR XML の結果の型をキャストする機能
  • FOR XML の結果を XML 型の変数に代入する機能
  • FOR XML クエリを入れ子にして XML 階層を生成する機能
  • 新しい PATH モードを使用して複雑な XML ドキュメントを生成する機能
  • XMLDATA オプションと XMLSCHEMA オプションを使用して、XDR または XSD 形式のインライン スキーマをそれぞれ生成する機能
  • RAW モードで ELEMENTS ディレクティブを使用して、要素中心の XML を生成する機能
  • XSINIL オプションと ELEMENT ディレクティブを併用して、属性が xsi:nil="true" の要素に NULL 値をマップする機能

OPENXML の機能強化

SQL Server 2005 では、以下の機能をサポートするように OPENXML が強化されました。

  • XML 型のデータを sp_xml_preparedocument に渡す機能
  • WITH 句で新しいデータ型を使用する機能

以下の場合、FOR XML と OPENXML を使用して XML ドキュメントを構成および分解することが適しています。

  • アプリケーションでデータをリレーショナルに格納し、この情報を別のアプリケーションに XML として公開する必要がある場合。
  • アプリケーションでは、XML の順序を保持する必要がない場合。
  • アプリケーションで、数多くの DML 操作を要素レベルで実行する場合。
  • アプリケーションで、きめ細かいデータ アクセスや更新が必要な場合。
  • アプリケーションで、Web サービス経由でリレーショナル データを公開する必要がある場合。

シナリオの分析

シナリオ 3 (「シナリオ 3: 自動車メーカーと自動車部品販売業者間でのデータ交換 2」を参照) の要件は、業者が請求書の状態を確認したり、支払い指図書のコピーを取得したりするために使用できる Web サービスを提供することです。 FOR XML と Web サービスを併用すると、メーカーがこれらのサービスをインターネット上で公開できるソリューションが提供されます。 業者は Web サービスを使用して、請求書の状態を確認します。 その後、Web サービスによって、業者が指定した請求書 ID が使用され、FOR XML ステートメントを使用してリレーショナル データから XML 形式の応答が生成されます。 生成された XML ドキュメントが業者に返されます。 現在のシナリオでは、FOR XML ステートメント ベースのアプローチを使用すると、以下のメリットを得られます。

  • FOR XML により、単純な XML ドキュメントをリレーショナル データから動的に構成することが容易になります。
  • 単純な XML ドキュメントを構成するために使用する場合、XML ビューと比較して FOR XML クエリの方が管理しやすくなります。

メリット

以下に、FOR XML および OPENXML を使用するメリットの一部を示します。

  • FOR XML によって、サーバーのリレーショナル データから XML を生成する簡単な方法が提供されます。
  • FOR XML には、Web サービスによってビジネス情報を公開する機能が用意されています。
  • OPENXML により、行セットを XML 形式でストアド プロシージャに渡すことができます。これにより、1 回のネットワーク ラウンドトリップで一括挿入、一括更新、一括削除操作を実行できます。
  • FOR XML と XSL は、アプリケーション統合またはビジネス統合で併用できます。

制限事項

XML ドキュメントの構成と分割に FOR XML または OPENXML を使用する場合の制限事項は、以下のとおりです。

  • FOR XML と EXPLICT オプションを併用して XML 構造を構築する作業が困難です。
  • FOR XML EXPLICIT を使用して記述した複雑なクエリを管理することが困難です。
  • FOR XML AUTO で生成した XML ドキュメントによって、データベース テーブル名や列情報が公開されることがあります。これにより、誤って情報が漏えいすることがあります。 この状況は、テーブルと列の別名を指定することで回避できます。

FOR XML と OPENXML の使用例

以下の例では、SQL Server 2005 に用意されている AdventureWorks データベースを使用します。FOR XML を使用して、指定した範囲の顧客の [Sales.Customer]、[Sales.SalesOrderHeader]、[Production.Product]、および [Sales.SalesOrderDetail] テーブルから、顧客、注文、注文の詳細情報を取得する例を見てみましょう。

例 : FOR XML の使用

SELECT Cust.CustomerID, 
       OrderHeader.CustomerID,
       OrderHeader.SalesOrderID, 
       Detail.SalesOrderID, Detail.LineNumber,Detail.ProductID, 
       Product.Name,
       Detail.OrderQty
FROM Sales.Customer Cust, 
     Sales.SalesOrderHeader OrderHeader,
     Sales.SalesOrderDetail Detail,
     Production.Product Product
WHERE Cust.CustomerID = OrderHeader.CustomerID
AND   OrderHeader.SalesOrderID = Detail.SalesOrderID
AND   Detail.ProductID = Product.ProductID
AND   (Cust.CustomerID BETWEEN 44 AND 46)
ORDER BY OrderHeader.CustomerID,
         OrderHeader.SalesOrderID
FOR XML AUTO

クエリの結果は以下のとおりです。

<Cust CustomerID="44">
  <OrderHeader CustomerID="44" SalesOrderID="53575">
    <Detail SalesOrderID="53575" LineNumber="2" ProductID="952" OrderQty="2">
      <Product Name="Chain" />
    </Detail>
    <Detail SalesOrderID="53575" LineNumber="1" ProductID="969" OrderQty="1">
      <Product Name="Touring-1000 Blue, 60" />
    </Detail>
    <Detail SalesOrderID="53575" LineNumber="3" ProductID="972" OrderQty="1">
      <Product Name="Touring-2000 Blue, 54" />
    </Detail>
  </OrderHeader>
  <OrderHeader CustomerID="44" SalesOrderID="59024">

    <Detail SalesOrderID="59024" LineNumber="1" ProductID="972" OrderQty="3">
      <Product Name="Touring-2000 Blue, 54" />
    </Detail>
    <Detail SalesOrderID="59024" LineNumber="2" ProductID="957" OrderQty="2">
      <Product Name="Touring-1000 Yellow, 60" />
    </Detail>
  </OrderHeader>
</Cust>
<Cust CustomerID="46">
  <OrderHeader CustomerID="46" SalesOrderID="48354">
    <Detail SalesOrderID="48354" LineNumber="1" ProductID="730" OrderQty="1">
      <Product Name="LL Road Frame - Red, 62" />
    </Detail>
  </OrderHeader>
</Cust>

次の例では、OPENXML と XPath 式を使用して XML ドキュメントで指定した注文の詳細情報を取り出します。

例 : OPENXML の使用

DECLARE @XmlDocumentHandle int
DECLARE @XmlDocument nvarchar(max)
SET @XmlDocument = N'<ROOT>
<Cust CustomerID="44">
  <OrderHeader CustomerID="44" SalesOrderID="53575">
    <Detail SalesOrderID="53575" LineNumber="2" ProductID="952" OrderQty="2">
      <Product Name="Chain" />
    </Detail>
    <Detail SalesOrderID="53575" LineNumber="1" ProductID="969" OrderQty="1">
      <Product Name="Touring-1000 Blue, 60" />
    </Detail>
    <Detail SalesOrderID="53575" LineNumber="3" ProductID="972" OrderQty="1">
      <Product Name="Touring-2000 Blue, 54" />
    </Detail>
  </OrderHeader>
  <OrderHeader CustomerID="44" SalesOrderID="59024">
    <Detail SalesOrderID="59024" LineNumber="1" ProductID="972" OrderQty="3">
      <Product Name="Touring-2000 Blue, 54" />
    </Detail>
    <Detail SalesOrderID="59024" LineNumber="2" ProductID="957" OrderQty="2">
      <Product Name="Touring-1000 Yellow, 60" />
    </Detail>
  </OrderHeader>
</Cust>
<Cust CustomerID="46">
  <OrderHeader CustomerID="46" SalesOrderID="48354">
    <Detail SalesOrderID="48354" LineNumber="1" ProductID="730" OrderQty="1">
      <Product Name="LL Road Frame - Red, 62" />
    </Detail>
  </OrderHeader>
</Cust>
</ROOT>'
-- XML ドキュメントの内部表現を作成します。
EXEC sp_xml_preparedocument @XmlDocumentHandle OUTPUT, @XmlDocument
-- OPENXML 行セット プロバイダを使用して、SELECT ステートメントを実行します。
SELECT *
FROM OPENXML (@XmlDocumentHandle, '/ROOT/Cust/OrderHeader/Detail',2)
WITH (CustomerID  varchar(10) '../@CustomerID',
      OrderID     int         '../@SalesOrderID',
      LineNumber  int         '@LineNumber',
      ProductID   int         '@ProductID',
      Quantity    int         '@OrderQty')
-- 内部表現を削除します。
EXEC sp_xml_removedocument @XmlDocumentHandle

クエリの結果は以下のとおりです。

--------------------------------------------------------
CustomerID   OrderID   LineNumber   ProductID   Quantity
--------------------------------------------------------
44      53575      2      952      2
44      53575      1      969      1
44      53575      3      972      1
44      59024      1      972      3
44      59024      2      957      2
46      48354      1      730      1
--------------------------------------------------------

SQL Server 2005 の XML データ型

XML データはその性質上階層構造になり、データ構造が複雑になるので (階層が深くなるなど)、XML データをリレーショナル データとしてモデル化することは困難です。 さらに、XML データをリレーショナル データにマップすると、XML インスタンスの要素の順序は保持されないので、分解したリレーショナル データから元の XML ドキュメントを構成するには、莫大なコストがかかります。 XML データを格納する場合のリレーショナル モデルの制限事項により、XML インスタンスをネイティブに格納できるのが理想的です。 ネイティブ XML インスタンスには、リレーショナル モデルの制限事項は影響せず、階層データや入れ子になったデータを処理する機能、要素の順序を保持する機能、XML データを簡単に格納および取得する方法、複数のスキーマをサポートする柔軟性などの機能が用意されています。

Microsoft SQL Server 2005 では、XML データ処理が幅広くサポートされます。 SQL Server 2005 の場合、XML の値はネイティブに XML データ型の列に格納できます。この列には、XML スキーマのコレクションに応じて型を指定することも、指定しないでおくこともできます。 XQuery および XML DML を使用して、きめ細かいデータ操作がサポートされます。XML DML は、データ変更の拡張機能です。 さらに、XML 列にインデックスを付けて、クエリ パフォーマンスを向上させることができます。

型指定された XML

型指定された XML の使用は、XML データを説明する XML スキーマがある場合に理想的です。 このような場合、XML スキーマのコレクションを XML 列と関連付けて、型指定された XML を生成できます。 XML 型の列での検証は、その列に関連付けられた XML スキーマ コレクションに基づいて実行されます。 また、型指定された XML データを必要とするクエリでは、ノード値を実行時に変換する必要がないので、クエリのパフォーマンスが型指定されていない XML データよりも優れています。

型指定されていない XML

型指定されていない XML の使用は、スキーマがあってもサーバーでデータを検証しない場合、または使用できるスキーマがない場合に適しています。 アプリケーションで以下の条件が満たされる場合、スキーマが存在しても、型指定されていない XML を格納できます。

  • 固定のスキーマがない場合。
  • サーバーでデータを格納する前に、クライアント側で検証が実行される場合。
  • スキーマに従って、無効な XML データを一時的に格納する場合。
  • サーバーでサポートされていないスキーマ コンポーネント (たとえば、key/keyref) が使用される場合。

型指定されていない XML ドキュメントは、スキーマに関連付けられていない場合でも、整形式であるかどうかを確認するためにチェックされます。 ノード値は Unicode 文字列として内部に格納されるので、ノード値が実行時に変換されることにより、型指定されていない XML のパフォーマンスが低下する点に注意することは重要です。

XML データ型の使用シナリオ

SQL Server 2005 の新しい XML データ型を使用して、以下の操作を実行できるようになりました。

  • リレーショナル列だけでなく、XML 型の 1 つ以上の列を含むテーブルを作成する。
  • XML 列を XML スキーマのコレクションを関連付けることで、型指定された XML 列を作成する。
  • ビジネス ルールを適用するために、他の XML 列または XML 以外の型の列を必要とする XML 列で制約を作成する。
  • XML データ型のインスタンスを格納するために使用できる XML 型の変数を作成する。
  • ストアド プロシージャまたはユーザー定義関数に対する XML 型のパラメータを作成する。
  • ユーザー定義関数から XML 型の値を返す。
  • 新しい TYPE ディレクティブを使用して取得した FOR XML クエリの結果を、XML 型の変数に代入する。
  • XQuery のサブセットを実行して XML 構造にクエリし、XML データを変換する。
  • XML 型の列に基づく計算列を作成する。
  • XML 型の列に XML インデックスを作成して、クエリのパフォーマンスを向上する。
  • XML DML を使用して、XML インスタンスで要素レベルの挿入、削除、更新操作を実行する。
  • XML 型のデータのインスタンスを sp_xml_preparedocument に渡して、XML ドキュメントのインメモリ表現を準備する。
  • XQuery と XML DML を使用して、リレーショナル列と XML 列の両方を含む領域をまたがるクエリを記述する。
  • CAST と CONVERT を使用して、XML 型を varchar 型または nvarchar 型にそれぞれキャストまたは変換する。
  • CAST または CONVERT を使用して、[n]varchar[n]textvarbinaryimage などの文字列データ型を XML 型に変換またはキャストする。

XML データ型のメソッドと XML DML

XML データ型の列でのクエリや操作は、5 つのメソッドによってサポートされます。 XML ドキュメントのフラグメントは、XML データ型の query() メソッドを使用して取り出すことができます。 query() メソッドでは、XQuery 式を引数として受け取り、型指定されていない XML インスタンスが返されます。 XQuery 式や返される SQL 型を指定することで、value() メソッドを使用して、XML インスタンスからスカラ値を取り出すことができます。 XML インスタンスでの存在確認は、exist() メソッドを使用して実行できます。 nodes() メソッドを使用することで、簡単に XML ドキュメントをリレーショナル データに分解できます。

modify() メソッドを使用すると、XML インスタンスでデータ操作を実行できます。 XQuery に追加された insert、delete、および update キーワードによって、XML DML がサポートされます。 insert、delete、および update キーワードをそれぞれ使用して、1 つ以上のノードを挿入、削除、および更新できます。

XML のインデックス設定

XML インスタンスのサイズが非常に大きい場合、XML データ型でのクエリ処理操作に関連する解析や分析に膨大な時間がかかることがあります。 XML データ型でのクエリ パフォーマンスは、これらの列にインデックスを作成して向上させることができます。 XML データのサイズや使用シナリオは、必要なインデックスの種類を決定するときに重要な要素となります。 SQL Server では、プライマリ XML インデックスとセカンダリ XML インデックスの 2 種類のインデックスがサポートされています。ただし、セカンダリ XML インデックスは、プライマリ XML インデックスがない場合は作成できません。

XML 列でプライマリ XML インデックスを作成すると、XML BLOB が分割され、これらの値が内部テーブルに格納されます。 このような分割は実行時には必要ありませんが、クエリ実行中にパフォーマンスが向上します。 使用シナリオによっては、セカンダリ XML インデックスを作成すると、クエリのパフォーマンスがさらに向上することがあります。 PATH、PROPERTY、VALUE の 3 種類のセカンダリ XML インデックスを作成し、パス、プロパティ、値に基づいて、クエリのパフォーマンスを向上させることができます。 XML 型の列に適切なセカンダリ インデックスを選択する方法の詳細については、「Performance Optimizations for the XML Data Type」 (英語) を参照してください。

以下の場合、XML ドキュメントを XML データ型として格納することが適しています。

  • アプリケーションで、XML インスタンスの Infoset コンテンツを保持する必要がある場合。 XML ドキュメントの Infoset コンテンツには、ドキュメント階層、要素の順序、要素や属性の値などが含まれます。 属性の順序、名前空間のプレフィックス、意味のない空白、XML 宣言などの情報は保持されません。
  • アプリケーションで、XML ドキュメントでの要素レベルの変更やクエリ操作が必要になる場合。
  • アプリケーションで、XML データ型の列にインデックスを設定して、クエリ処理を速くする必要がある場合。
  • XML データのスキーマの有無がはっきりしない場合。
  • アプリケーションで、さまざまな構造を持つ XML ドキュメント、または難しすぎてリレーショナル構造にマップできない異なるスキーマまたは複雑なスキーマに準拠する XML ドキュメントが使用される場合。

シナリオの分析

シナリオの分析 : コンテンツ管理システム

ここでは、前述のコンテンツ管理システム (「シナリオ 4: コンテンツ管理システム」を参照) を分析しましょう。 出版社では、文字、画像、オーディオ、ビデオなどのさまざまな形式の情報を処理します。単独で使用できるまとまった情報が、さまざまな情報源から収集され、データベースで管理されます。 このようなまとまった情報を、"コンポーネント" と呼びます。 個別のコンポーネントを組み立てることで、ドキュメントが作成されます。 どのようなコンポーネントがドキュメントに含まれるかは、ユーザーの要件によって異なります。 これらのドキュメントは、さまざまな媒体を使用して、購読するユーザーに配信されます。 通常、コンテンツ管理システムには、高いパフォーマンスとスケーラビリティでコンテンツを格納、取得、検索、更新する機能など、いくつかの要件があります。

統一されたデータ モデルとしての XML には、XML データと XML コンテンツの両方を 1 つのドキュメントに格納するための魅力的なオプションが用意されています。 また、XML には、表示をデータ自体から切り離す機能も用意されています。同じ情報でも、表示はユーザーごとに異なる場合があるので、この機能は重要です。 SQL Server 2005 によって提供されるネイティブ XML データ型を使用して、このコンテンツ管理システムの要件を満たすことができます。 XML データ型を使用すると、XML ドキュメントの格納、XML DML を使用した要素レベルでの XML ドキュメントの変更、および XQuery を使用した XML ドキュメントでのクエリの実行を行うことができます。

シナリオの分析 : 顧客アンケート

顧客アンケートの XML 使用シナリオ (「シナリオ 5: 顧客アンケート」を参照) の重要な要件は、複数のスキーマを使用して調査情報を格納する機能です。 固定のスキーマのないデータは、1 つのリレーショナル テーブルを使用してモデル化することはできません。 XML 列を含むリレーショナル テーブルには、そのような情報を格納するための優れたオプションが用意されています。 リレーショナル テーブルに新たな列を追加して、アンケートの種類を格納できます。 特定の種類のアンケートに対応する情報は、そのアンケートの種類の列を使用して、その種類のすべてのレコードをフェッチすることで分析できます。 通常、一般的なアンケートでは、顧客がすべての質問には回答するわけではありません。 したがって、(アンケートの質問ごとに 1 列ずつ) 複数の列を作成し、回答されなかった質問に対してデータベースに NULL 値を格納するのではなく、顧客ごとのアンケート情報を XML ドキュメントとして 1 つの列に格納することが役に立ちます。 このシナリオでは、顧客のアンケート情報を XML 型の列として格納するのが適切です。以下に、その理由を示します。

  • XML 型の列を使用すると、さまざまなスキーマによるアンケート情報を 1 つの XML 型の列に格納できます。 ユーザーは、XML 型の列を XML スキーマ コレクションと関連付けて、複数の種類のアンケートに関するデータを格納できます。
  • アンケート情報の検証をユーザー インターフェイスから実行できます。また、データベース レベルで検証を実行するために、アンケート情報を型指定された XML データ型の列として格納する必要がありません。
  • XQuery を使用して、データを分析できます。

メリット

XML データを XML データ型の列に格納するメリットは、以下のようにまとめることができます。

  • XML データ型により、ドキュメントの順序や構造を保ちながら、サーバーで XML データを格納するための単純かつ簡単な方法が提供されます。 このことは、特に、ドキュメントの順序や構造が非常に重要なドキュメントに当てはまります。 アプリケーションによって、あるデータ ソースから XML ドキュメントが取得され、そのドキュメントが格納されるサンプル シナリオを想定しましょう。 ドキュメントを nvarchar 列または text 列に格納しても、整形式の XML は保証されず、ドキュメントのコンテンツに簡単にアクセスすることはできません。 そのような場合は、着信 XML ドキュメントを XML 列にネイティブに格納することが適しています。
  • XML データ型には、XML データできめ細かいクエリを実行し、操作を変更する機能が用意されています。 SQL Server 2005 より前のバージョンでは、XML をデータベースにネイティブに格納する方法はありませんでした。 そのため、XML データの変更やクエリを行う場合は、データを nvarchar 列または text 列から読み込み、XML ドキュメントをその文字列から作成して、変更する必要がありました。 変更したデータをデータベースに戻す場合も、同様の手順を実行する必要がありました。 XML データ型により、このような手順が非常に容易になります。
  • XML データ型を使用して XML データ型の列にインデックスを設定し、クエリ処理を高速にできます。
  • XML データ型を使用すると、XML データで XML スキーマ コレクションと制約を使用して、ビジネス ルールを適用できます。 XML スキーマを使用して、データを検証し、型ベースの操作の意味合いを加え、クエリやデータ変更ステートメントのコンパイル中に型指定されていない XML よりも正確な型チェックを実行し、ストレージやクエリ処理を最適化します。
  • XML 型のデータはデータベースに格納されるので、バックアップと復元、SQL Server セキュリティ、トランザクション、ログ記録などのさまざまなデータベース アクティビティの対象になります。

制限事項

以下に、新しい XML データ型を使用して作業するときに注意する必要がある一部の制限事項を示します。

  • データの正確なコピーが格納されません。 意味のない空白、名前空間のプレフィックス、属性の順序、および XML 宣言が保持されません。
  • XML ドキュメントの階層の深さが、最大で 128 までです。
  • XML ドキュメントの内部バイナリ表記のサイズは、最大で 2 GB までです。
  • XML インスタンス同士を比較できません。 したがって、以下のようになります。
    • XML 列を主キー制約または外部キー制約の一部にすることができません。
    • XML 列を GROUP BY ステートメントでグループ化の値として使用できません。

textntext、および image データ型は SQL Server 2005 では推奨されないので、これらのデータ型に XML をキャストできません。ただし、[n]varchar 型および [n]varbinary 型には、XML データ型をキャストできます。

XML データ型の使用例

サンプル アプリケーションでは、AdventureWorks データベースの Sales.Store テーブルを使用します。 Sales.Store テーブルには、主キーとして CustomerID が、XML 列として Demographics が含まれています。 Demographics 列には、店舗の調査情報が含まれています。 店舗調査として格納される情報の一部は、省略可能です。 つまり、Demographics 列には、すべての要素が含まれるかどうかはわかりません。 同じ情報をリレーショナル形式で格納する場合、調査情報の各要素をテーブルの列として作成する必要があります。 大部分の店舗調査情報は省略可能で、省略された列には NULL 値が含まれます。つまり、大部分のデータに NULL 値が含まれることになります。 そのため、テーブルの領域が無駄に消費されることになります。 このような浪費を避けるために、店舗調査情報を Demographics 列に XML 形式で格納します。 Demographics 列には、販売情報 (つまり、年間売上高、歳入、銀行名など) が顧客ごとに含まれています。 これらのフィールドは、XML 要素としてデータに格納されます。

サンプル アプリケーションでは、以下の機能が実行されます。

  • すべての顧客の一覧を販売統計情報と共に表示します。
  • 特定の顧客の販売統計情報を表示します。
  • 新しい顧客を販売統計情報と共に Sales.Store テーブルに挿入します。
  • 指定された顧客の販売統計情報の一部の要素 (年間売上高、歳入など) を変更します。
  • 指定された顧客の販売統計情報を削除します。

アプリケーションでは、System.Data.SqlTypes.SqlXml クラスを使用して、XML 列からデータを取得します。 SQLXML クラスは、XML 列への直接マッピングです。

SQLXML クラスを使用すると、マッピングまたは変換を行わずに、XML 列からデータを直接取得できます。

ここで、顧客 ID 12 の歳入要素を取得する方法の例を見てみましょう。次のコードの例は、上記の 2 番目の機能を示しています。

Public void RetreiveAnnualRevenue ()
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = @"Server=localhost; Database=AdventureWorks;
integrated security=SSPI";
   conn.Open();
   SqlCommand command = conn.CreateCommand();
   command.CommandText = @"select Demographics.query(
'declare namespace SS="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/StoreSurvey"
<StoreInfo>

 <AnnualRevenue>
{data(/SS:StoreSurvey/SS:AnnualRevenue)}
   </AnnualRevenue>
</StoreInfo>') as
Result from Sales.Store where CustomerID=12";
   SqlDataReader datareader = command.ExecuteReader();
System.Text.StringBuilder builder = new System.Text.StringBuilder();
   While (datareader.Read())
   {
      SqlXml sqlxml = datareader.GetSqlXml(0);
      builder.Append(sqlxml.Value);
   }
   // 注 : xml1 は XML Web コントロールです。
   this.xml1.DocumentContent = builder.ToString();
this.xml1.TransformSource = @"StoreInfo.xslt";
}

上記の方法により、SqlConnection オブジェクトのインスタンスが AdventureWorks データベースに作成されます。 コマンド テキストのプロパティには、顧客 ID 12 の歳入フィールドの値を取得するクエリが含まれています。

これは、XML 列で直接実行される XQuery です。 クエリの戻り値は XML フラグメントで、SQLXML クラスにマップされます。 その後、SQLXML クラスの Value プロパティを使用して、XML フラグメントを取得できます。

取得した XML フラグメントは、XML Web サーバー コントロールを使用してクライアント アプリケーションに表示されます。

さまざまなアプローチの比較

機能 .NET Framework の XML クラス FOR XML / OPENXML SQLXML XML データ型
コードの複雑さ 高。 XML データとリレーショナル データ間を直接マップするクラスはありません。 中。 FOR XML EXPLICIT を使用してクエリを記述することは困難です。 低。 クラスには、リレーショナル データを XML データとして操作するためのメカニズムが用意されています。また、アップデートグラムには、レコードを更新する機能が用意されています。 低。 XML データ自体が列に格納されるので、あまり複雑ではありません。 さらに、Visual Studio 2005 には、XML データ型を操作するためのクラスが備わっています。 XML データの変更に XML DML を使用できます。
管理の容易性 複雑。 テーブルのフィールドや XML を変更するには、コードを変更する必要があります。 困難。 テーブルのフィールドや XML を変更するには、クエリを変更する必要があります。 容易。 大部分の場合、マッピング XSD ファイルを変更することで、変更に対応できます。 容易。 XQuery によって、データベース内の XML 列をクエリする簡単な構文が提供されます。
インストール .NET Framework を除いて、特別なインストールは必要ありません。 特別なインストールは必要ありません。 SQLXML ライブラリがクライアント コンピュータにインストールされている必要があります。 特別なインストールは必要ありません。
セキュリティ 通常、データ型と書式設定はクライアント側で公開されないので、セキュリティで保護される程度が非常に高くなります。 テーブル名や列名の漏えいを避けることを十分注意すれば、セキュリティで保護されます。 マッピング XSD ファイルが中間層ではなく、クライアント側に格納される場合、デザインによりセキュリティで保護する必要があります。 セキュリティで保護されています。
.NET Compact Framework のサポート サポートが制限されます。 XmlDataDocument は、Microsoft .NET Compact Framework でサポートされません。 サポートされます。 サポートされません。 サポートされません。 SQL Server の XML データ型の列は、SQL Server Mobile に同期される場合、ntext に変換されます。
データ検証 クライアントとサーバーで実行できます。 サーバーで実行できます。 クライアントで実行できます。 XML スキーマを使用してサーバーで実行できます。
データ ストレージ [n]varchar(max)、XML、または varbinary(max)。 リレーショナル テーブル (XML をフィールドとして使用できます)。 リレーショナル テーブル (XML をフィールドとして使用できます)。 XML データ型。
再現性 テキストの再現性 (バイト レベルで XML データを保持します)。 リレーションの再現性 (データの階層構造は保持されますが、要素間の順序は無視されます)。 リレーションの再現性。 InfoSet の再現性 (XML データの InfoSet コンテンツを保持します)。
ストアでのデータ アクセスと更新 ドキュメント レベルで更新をサポートします。 きめ細かいデータ アクセスや更新をサポートします。 きめ細かいデータ アクセスや更新をサポートします。 きめ細かいデータ アクセスや更新をサポートします。

まとめ

この資料では、SQL Server 2005 で XML を処理するためのさまざまなオプションを紹介しています。System.Xml 名前空間、SQLXML、および XML データ型については、それぞれの関連するメリットと制限事項を同時に説明し、サンプル シナリオも含めています。 ユーザーは、典型的なシナリオで示されているパフォーマンスを調べることにより、アプリケーションに適切な XML オプションを選択できます。

関連情報

Microsoft SQL Server 2005 Web サイト

Microsoft SQL Server 2005 での XML サポート

Microsoft SQL Server 2005 での XML のベスト プラクティス

Microsoft SQL Server 2005 での FOR XML の新機能

XML データ型のパフォーマンスの最適化