FOR XML 句を使用するためのガイドライン
FOR XML 句は、最上位レベルのクエリとサブ クエリのいずれでも使用できます。最上位レベルの FOR XML 句は、SELECT ステートメント内でのみ使用できます。サブ クエリでは、FOR XML 句を INSERT、UPDATE、DELETE ステートメント内で使用できます。また、代入ステートメントでも使用できます。次に例を示します。
DECLARE @x xml
SET @x = (SELECT *
FROM Sales.Customer
FOR XML AUTO, TYPE)
SELECT @x
TYPE ディレクティブにより、クエリの結果が xml 型で返されることに注意してください。TYPE ディレクティブを追加しないと、FOR XML クエリの結果が nvarchar(max) 型で返されます。この結果は、その後 xml に変換され、xml 型の変数に代入されます。
FOR XML 句には、次の制限事項が適用されます。
COMPUTE BY 句または FOR BROWSE 句で使用されるどのような選択に対しても FOR XML は無効です。たとえば、次のクエリを実行するとエラーが発生します。
SELECT TOP 5 SalesOrderID, UnitPrice FROM Sales.SalesOrderDetail ORDER BY SalesOrderID COMPUTE SUM(UnitPrice) BY SalesOrderID FOR XML AUTO
TYPE ディレクティブを指定していない最上位レベルでの FOR XML 句は、カーソルと共に使用できません。
FOR XML 句を伴う SELECT ステートメントが、クエリの中で 4 つの部分から構成される名前を指定している場合、クエリがローカル コンピュータ上で実行されると、結果の XML ドキュメントにサーバー名は返されません。しかし、クエリがネットワーク サーバー上で実行されると、4 つの部分から構成される名前でサーバー名が返されます。
たとえば、次のクエリについて考えてみます。SELECT TOP 1 LastName FROM ServerName.AdventureWorks.Person.Contact FOR XML AUTO
ServerName
がローカル サーバーの場合、クエリは次の値を返します。<AdventureWorks.Person.Contact LastName="Achong" />
ServerName
がネットワーク サーバーの場合、クエリは次の値を返します。<ServerName.AdventureWorks.Person.Contact LastName="Achong" />
次の別名を指定することによって、このような違いが生じないようにできます。
SELECT TOP 1 LastName FROM ServerName.AdventureWorks.Person.Contact x FOR XML AUTO
このクエリの結果は次のようになります。
<x LastName="Achong"/>
また、スペースなど、XML では無効になる文字を含む SQL Server の名前は、その無効な文字をエスケープ数値エンティティ エンコードに変換する方法で XML 名に変換されます。
XML の名前に使用できる英字以外の文字はコロン (:) とアンダースコア (_) の 2 つだけです。コロンは既に名前空間用に予約されているので、エスケープ文字としてはアンダースコアが使われます。エンコードに使用されるエスケープの規則は、次のとおりです。
有効な XML 名の文字ではない UCS-2 文字は、XML 1.0 の仕様に従って、_xHHHH_ としてエスケープされます。この HHHH は、その文字の 4 桁の 16 進数 UCS-2 コードを最上位ビットから順に表しています。たとえば、テーブル名 Order Details は、Order_x0020_Details のようにエンコードされます。
UCS-2 領域に適合しない文字 (U+00010000 ~ U+0010FFFF の範囲の UCS-4 追加分) は、_xHHHHHHHH_ のようにエンコードされます。SQL Server 2000 以前の下位互換性モードで実行されている場合、この HHHHHHHH は、その文字の 8 桁の 16 進数 UCS-4 エンコードを表します。それ以外の場合は、SQL-2003 標準に合わせ、文字は _xHHHHHH_ の形式でエンコードされます。
アンダースコア文字は、その後に文字 x が続いていない場合はエスケープする必要はありません。たとえば、テーブル名 Order_Details はエンコードされません。
識別子内のコロン (:) 文字はエスケープされません。このため、FOR XML クエリで名前空間の要素と属性名を生成できます。たとえば、次のクエリでは名前にコロンが含まれる名前空間属性が生成されます。
SELECT 'namespace-urn' as 'xmlns:namespace', 1 as 'namespace:a' FOR XML RAW
クエリの結果は以下のとおりです。
<row xmlns:namespace="namespace-urn" namespace:a="1"/>
XML 名前空間を追加する場合は、WITH XMLNAMESPACES を使用することをお勧めします。
SELECT クエリで、BLOB (バイナリ ラージ オブジェクト) に任意の列をキャストした場合、列は一時エンティティになります (関連するテーブル名と列名が失われます)。これにより、AUTO モードのクエリでエラーが発生します。これは XML 階層内でのこの値の配置場所がわからないためです。次に例を示します。
CREATE TABLE MyTable (Col1 int PRIMARY KEY, Col2 binary) INSERT INTO MyTable VALUES (1, 0x7)
次のクエリでは、BLOB (バイナリ ラージ オブジェクト) へのキャストによるエラーが発生します。
SELECT Col1, CAST(Col2 as image) as Col2 FROM MyTable FOR XML AUTO
これを解決するには、BINARY BASE64 オプションを FOR XML 句に追加します。キャストを削除すると、クエリは予想どおりの結果を作成します。
SELECT Col1, Col2 FROM MyTable FOR XML AUTO
次に結果を示します。
<MyTable Col1="1" Col2="dbobject/MyTable[@Col1='1']/@Col2" />
SQL Server 2000 では、FOR XML の出力に無効な XML 文字が含まれる可能性があります。たとえば、16 進数値 7 は書式文字として使用されますが、それ以外については通常、出力ではテキストとして表示されます。SQL Server 2005 では、TYPE ディレクティブが指定されていない FOR XML クエリの結果として返される場合、このような文字をエンティティに変換します。
XML 1.0 準拠のパーサーは、これらの文字がエンティティであるかどうかにかかわらず解析エラーを返しますが、エンティティで表現すると XML 1.1 への準拠度が高くなります。エンティティによる表現は、XML 標準の今後のバージョンでも推奨されると考えられます。また、コード内で無効な文字を検出しやすくなるため、デバッグが容易になります。
XML ツールを使用している場合は、データ ストリーム中で無効な文字が見つかった場合は、どのような場合でも XML パーサーは失敗するので、対処する必要はありません。XML 以外のツールを使用している場合は、エンティティとして表現すべき文字を検索するようにプログラミング ロジックを変更する必要が生じる可能性があります。SQL Server 2005 では、FOR XML クエリ内の以下の空白文字が情報のやり取りの間に失われないようにするため、異なるエンティティに変換されます。
- 要素のコンテンツおよび属性内 : hex(0D) (キャリッジ リターン)
- 属性のコンテンツ内 : hex(09) (タブ)、hex(0A) (ライン フィード)
このため、このような文字が正規化された SQL Server 2000 の出力を処理するように設計されていたアプリケーションは、影響を受ける可能性があります。SQL Server 2005 の出力では、これらの文字は保持され、パーサーはこれらの文字を正規化しません。