XQuery と静的な型指定
適用対象: SQL Server
SQL Server の XQuery は、静的に型指定された言語です。 つまり、式が特定の関数または演算子で受け入れられない型またはカーディナリティを持つ値を返すと、クエリのコンパイル中に型エラーが発生します。 さらに、静的な型チェックでは、型指定された XML ドキュメントのパス式が誤って入力されているかどうかを検出することもできます。 XQuery コンパイラは、アトミック化などの暗黙的な操作を加える正規化を適用してから、静的な型の推定および確認を行います。
静的な型の推定
静的な型の推定では、式の戻り型が判定されます。 この判定は、入力パラメーターの静的な型および演算の静的なセマンティクスを取得し、結果の静的な型を推定することで行われます。 たとえば、式 1 + 2.3 の静的な型は、次のように決定されます。
- 静的型 1 は xs:integer で、静的型 2.3 は xs:decimal です。 動的セマンティクスに基づいて、 + 操作の静的セマンティクスは整数を 10 進数に変換し、10 進数を返します。 推定される静的型は、 xs:decimal になります。
型指定されていない XML インスタンスの場合、データが型指定されていないことを示す特殊な型があります。 その情報は、静的な型チェックのときに暗黙的に型をキャストするために使用されます。
型指定されたデータの場合、XML データ型インスタンスを制約する XML スキーマ コレクションから入力の型が推定されます。 たとえば、スキーマで xs:integer型の要素のみが許可されている場合、その要素を使用するパス式の結果は、 xs:integer 型の 0 個以上の要素になります。 現在、これは、アスタリスク (*) が結果の型のカーディナリティを示す element(age,xs:integer)*
などの式を使用して表されます。 この例では、式の名前 "age" と型 xs:integer の要素が 0 個以上になる可能性があります。 その他のカーディナリティは厳密に 1 であり、型名のみを使用して表され、0 または 1 を使用し、疑問符 (?) を使用して表され、1 つ以上が正符号 (+) を使用して表されます。
場合によっては、静的な型推論では、式が常に空のシーケンスを返す可能性があります。 たとえば、型指定された XML データ型のパス式で、<customer> 要素 (/customer/name) 内で <name> 要素を検索するが、スキーマで <customer> 内の<名>が許可されていない場合、静的型推論では結果が空であると推論されます。 これは、不適切なクエリを検出するために使用され、式が () または data( () )でない限り、静的エラーとして報告されます。
詳細な推論規則は、XQuery 仕様の正式なセマンティクスで提供されています。 マイクロソフトでは、型指定された XML データ型のインスタンスに対応するためにこの規則を少しだけ変更しました。 標準からの最も重要な変更点は、暗黙的なドキュメント ノードで XML データ型のインスタンスの型を認識することです。 その結果、/age 形式のパス式は、その情報に基づいて正確に型指定されます。
SQL Server プロファイラーテンプレートと権限を使用すると、クエリ コンパイルの一部として返される静的な型を確認できます。 これらを確認するには、トレースに TSQL イベント カテゴリの XQuery Static Type イベントが含まれている必要があります。
静的な型チェック
静的な型チェックにより、実行時の実行は、操作に適した型の値のみを受け取ります。 実行時には必ずしも型がチェックされるとは限りませんが、コンパイルの初期段階で潜在的なエラーを検出できます。 これにより、パフォーマンスが向上します。 ただし、静的な型指定を使用する場合、クエリの記述には通常以上の配慮が必要になります。
次に、使用できる適切な型を示します。
関数または操作によって明示的に許可される型。
明示的に許可されている型のサブタイプ。
サブタイプは、XML スキーマの制約または拡張による派生を使用するためのサブタイプ指定規則に基づいて定義されます。 たとえば、型が S であるすべての値が型 T のインスタンスでもある場合、型 S は型 T のサブタイプです。
さらに、すべての整数値は、XML スキーマ型階層に基づく 10 進値でもあります。 一方、decimal 型のすべての値が integer 型の値であるとは限りません。 したがって、整数は 10 進数のサブタイプですが、その逆ではありません。 たとえば、 + 操作では、数値型 xs:integer、 xs:decimal、 xs:float、 xs:double など、特定の型の値のみを使用できます。 xs:string などの他の型の値が渡されると、この操作によって型エラーが発生します。 これは、厳密な型指定と呼ばれます。 型指定されていない XML を示すために使用されるアトミック型など、他の型の値は、操作が受け入れる型の値に暗黙的に変換できます。 これは弱い型指定と呼ばれます。
暗黙的な変換の後での静的な型チェックを必須にした場合、カーディナリティが正しく、許可された型の値のみが演算に渡されます。 "string" + 1 の場合、"string" の静的型が xs:string であることを認識します。 これは + 操作で許可される型ではないため、型エラーが発生します。
任意の式 E1 の結果に任意の式 E2 を加算する (E1 + E2) 場合、静的な型の推定によって E1 および E2 の静的な型が判定されたうえで、それらの型が演算に許可されている型であるかどうかのチェックが行われます。 たとえば、E1 の静的型に xs:string または xs:integer を指定できる場合、実行時に一部の値が整数であっても、静的な型チェックで型エラーが発生します。 E1 の静的型が xs:integer* の場合も同様です。 +操作は 1 つの整数値のみを受け取り、E1 は 0 または 1 を超える値を返すことができるため、静的な型チェックではエラーが発生します。
前述のように、型推論では、渡されるデータの型についてユーザーが知っているものよりも広い型が推論されることが多いです。 そのような場合は、ユーザーがクエリを書き換える必要があります。 一般的なケースには、次のようなものがあります。
スーパータイプまたは型の共用体など、汎化された型が推定される。 型がアトミック型の場合は、キャスト式またはコンストラクター関数を使用して、実際の静的型を示す必要があります。 たとえば、式 E1 の推論された型が xs:string または xs:integer を選択し、加算に xs:integer が必要な場合は、
E1+E2
ではなくxs:integer(E1) + E2
を記述する必要があります。 この式は、 xs:integerにキャストできない文字列値が検出された場合に、実行時に失敗する可能性があります。 ただし、この式は静的な型チェックには合格します。 この式は空のシーケンスにマップされます。データの実際の内容を上回るカーディナリティが推定される。 これは、 xml データ型に複数の最上位要素を含めることができるため、頻繁に発生します。XML スキーマ コレクションではこれを制約できません。 静的な型を限定し、渡される値の数を 1 以下にするためには、位置関係の述語
[1]
を使用してください。 たとえば、最上位レベルの要素のb
要素の属性c
の値に 1 を追加するには、write (/a/b/@c)[1]+1
する必要があります。 さらに、DOCUMENT キーワードは XML スキーマ コレクションと共に使用できます。一部の操作では、推論中に型情報が失われます。 たとえば、ノードの種類を特定できない場合は、 anyType になります。 これは暗黙的に他の型にキャストされません。 これらの変換は、親軸を使用してナビゲーション中に最も顕著に発生します。 式で静的な型のエラーが発生する場合、そのような演算の使用は避け、クエリを書き換えてください。
共用体型の型チェック
共用体型では、型チェックのために慎重な処理が必要です。 次の例では、2 つの問題を示します。
例: 和集合型に対する関数
共用体型の <r
> の要素定義について考えてみましょう。
<xs:element name="r">
<xs:simpleType>
<xs:union memberTypes="xs:int xs:float xs:double"/>
</xs:simpleType>
</xs:element>
XQuery コンテキスト内では、XQuery コンパイラは、fn:avg() の引数の<r
>要素に対して異なる型 (xs:int、xs:float または xs:double) の値を追加できないため、"average" 関数fn:avg (//r)
は静的エラーを返します。 これを解決するには、関数の呼び出し部分を「fn:avg(for $r in //r return $r cast as xs:double ?)
」と書き換えます。
例: 和集合型の演算子
加算演算 ('+') には、オペランドの正確な型が必要です。 その結果、式 (//r)[1] + 1
は、要素 <r
>の前に説明した型定義を持つ静的エラーを返します。 解決策の 1 つは、「(//r)[1] cast as xs:int? +1
」("?" は 0 回または 1 回の出現を示す) に書き換える方法です。 SQL Server では、実行時エラーの結果として空のシーケンスが発生する可能性があるため、"?"" で "キャスト" が必要です。