型システム (XQuery)

XQuery は、スキーマ型に対しては厳密に型指定された言語で、型指定されていないデータに対しては厳密には型指定されていない言語です。XQuery の定義済みの型には、次のものがあります。

このトピックでは、次の内容についても説明します。

XML スキーマの組み込み型

XML スキーマの組み込み型には、xs という定義済みの名前空間プレフィックスが付いています。このような型には、xs:integerxs:string などがあります。これらの組み込み型はすべてサポートされます。XML スキーマ コレクションを作成するときに、これらの型を使用できます。

型指定された XML のクエリを実行するとき、ノードの静的および動的な型は、クエリの対象の列または変数に関連付けられた XML スキーマ コレクションによって決まります。静的および動的な型の詳細については、「式コンテキストとクエリの評価 (XQuery)」を参照してください。たとえば、次のクエリは型指定された xml 列 (Instructions) に対して指定されています。この式では instance of を使用して、返される LotSize 属性の型指定された値が xs:decimal 型であることを確認しています。

SELECT Instructions.query('
   DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   data(/AWMI:root[1]/AWMI:Location[@LocationID=10][1]/@LotSize)[1] instance of xs:decimal
') AS Result
FROM Production.ProductModel
WHERE ProductModelID=7

この型指定情報は、列に関連付けられた XML スキーマ コレクションによって提供されます。詳細については、「AdventureWorks データベースの xml データ型表現」を参照してください。

XPath データ型の名前空間で定義されている型

http://www.w3.org/2004/07/xpath-datatypes 名前空間で定義されている型には、xdt という定義済みのプレフィックスが付いています。これらの型には、次のことが当てはまります。

  • XML スキーマ コレクションを作成しているときは、これらの型を使用できません。これらの型は XQuery の型システムで使用され、静的な型指定に使用されます。xdt 名前空間の xdt:untypedAtomic などのアトミック型にキャストできます。
  • 型指定されていない XML のクエリでは、要素ノードの静的および動的な型は xdt:untyped で、属性値の型は xdt:untypedAtomic になります。query() メソッドの結果により、型指定されていない XML が生成されます。つまり、XML ノードはそれぞれ xdt:untypedxdt:untypedAtomic として返されます。
  • xdt:dayTimeDuration 型と xdt:yearMonthDuration 型はサポートされません。

次の例では、型指定されていない XML 変数に対してクエリを指定しています。式 data(/a[1]) により、1 つのアトミック値のシーケンスが返されます。data() 関数により、要素 <a> の型指定された値が返されます。クエリ対象の XML は型指定されていないので、返される値は xdt:untypedAtomic 型です。したがって、instance of から True が返されます。

DECLARE @x xml
SET @x='<a>20</a>'
SELECT @x.query( 'data(/a[1]) instance of xdt:untypedAtomic' )

次の例の式 (/a[1]) は、型指定された値を取得するのではなく、要素 <a> という 1 つの要素のシーケンスを返します。instance of 式では要素をテストすることにより、式から返される値が xdt:untyped 型の要素ノードであることを確認します。

DECLARE @x xml
SET @x='<a>20</a>'
-- Is this an element node whose name is "a" and type is xdt:untyped.
SELECT @x.query( '/a[1] instance of element(a, xdt:untyped?)')
-- Is this an element node of type xdt:untyped.
SELECT @x.query( '/a[1] instance of element(*, xdt:untyped?)')
-- Is this an element node?
SELECT @x.query( '/a[1] instance of element()')
ms177483.note(ja-jp,SQL.90).gifメモ :
型指定された XML インスタンスにクエリを実行して、クエリ式に parent 軸が含まれるときは、結果のノードの静的な型情報は使用できなくなります。ただし、動的な型はノードに関連付けられたままです。

型指定された値と文字列値

どのノードにも型指定された値と文字列値があります。型指定された XML データの場合、型指定された値の型は、クエリ対象の列または変数に関連付けられた XML スキーマ コレクションによって提供されます。型指定されていない XML データの場合、型指定された値は xdt:untypedAtomic 型になります。

次のように data() 関数または string() 関数を使用して、ノードの値を取得できます。

  • data 関数では、ノードの型指定された値が返されます。
  • string 関数では、ノードの文字列値が返されます。

次の XML スキーマ コレクションでは、整数型の <root> 要素を定義しています。

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" type="integer"/>
</schema>'
GO

次の例の式では、最初に /root[1] の型指定された値を取得してから、その値に 3 を加算しています。

DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('data(/root[1]) + 3')

次の例では、式の string(/root[1]) から文字列型の値が返されるので、式が失敗します。返された値は、オペランドとして数値型の値しか受け取らない算術演算子に渡されます。

-- Fails because the argument is string type (must be numeric primitive type).
DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('string(/root[1]) + 3')

次の例では、LaborHours 属性の合計を計算しています。data() 関数により、製品モデルのすべての <Location> 要素から LaborHours 属性の型指定された値が取得されます。Instruction 列に関連付けられた XML スキーマに従って、LaborHoursxs:decimal 型になります。

SELECT Instructions.query(' 
DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
             sum(data(//AWMI:Location/@LaborHours)) 
') AS Result 
FROM Production.ProductModel 
WHERE ProductModelID=7

このクエリにより、結果として 12.75 が返されます。

ms177483.note(ja-jp,SQL.90).gifメモ :
この例では data() 関数を、説明のみを目的として明示的に使用しています。この関数を指定しないと、sum() では、ノードの型指定された値を取得する data() 関数が暗黙的に適用されます。

シーケンス型の照合

XQuery 式の値は必ず 0 個以上のアイテムのシーケンスになります。アイテムはアトミック値またはノードのいずれかです。シーケンス型とは、クエリ式から返されたシーケンス型を特定の型と照合する機能のことです。次に例を示します。

  • 式の値がアトミックの場合、その値が整数型、小数型、または文字列型であるかどうかを確認できます。
  • 式の値が XML ノードの場合、その値がコメント ノード、処理命令ノード、またはテキスト ノードであるかどうかを確認できます。
  • 式から特定の名前や型の XML 要素または属性ノードが返されるかどうかを確認できます。

シーケンス型の照合では、instance of ブール演算子を使用できます。instance of 式の詳細については、「SequenceType 式 (XQuery)」を参照してください。

式から返されるアトミック値の型の比較

式からアトミック値のシーケンスが返される場合、シーケンス内の値の型を確認することが必要な場合があります。次の例は、シーケンス型の構文を使用して式から返されるアトミック値の型を評価する方法を示しています。

例 A

指定された式から返されるシーケンスが空のシーケンスであるかどうかを判断するには、シーケンス型の式で empty() シーケンス型を使用できます。

次の例の XML スキーマでは、<root> 要素を NULL にできます。

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

この場合、型指定された XML インスタンスで <root> 要素に値を指定すると、instance of empty() から False が返されます。

DECLARE @var XML(SC1)
SET @var = '<root>1</root>'
-- The following returns False
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

インスタンスの <root> 要素を NULL にすると、要素の値は空のシーケンスになり、instance of empty() から True が返されます。

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />'
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

例 B

場合によっては、式から返されるシーケンス型を処理前に評価することが必要なことがあります。たとえば、ノードが union 型として定義されている XML スキーマを使用している場合です。次の例では、コレクションの XML スキーマで、値を小数型または文字列型にすることができる union 型として属性 a を定義しています。

-- Drop schema collection if it exists.
-- DROP XML SCHEMA COLLECTION SC.
-- GO
CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="root">
    <complexType>
       <sequence/>
         <attribute name="a">
            <simpleType>
               <union memberTypes="decimal string"/>
            </simpleType>
         </attribute>
     </complexType>
  </element>
</schema>'
GO

型指定された XML インスタンスを処理する前に、属性 a の値の型を確認できます。次の例では、属性 a の値は小数型です。そのため、instance of xs:decimal から True が返されます。

DECLARE @var XML(SC)
SET @var = '<root a="2.5"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:decimal')
GO

ここで、属性 a の値を文字列型に変更します。この場合でも、instance of xs:string から True が返されます。

DECLARE @var XML(SC)
SET @var = '<root a="Hello"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:string')
GO

例 C

この例は、シーケンス式の基数の効果を示しています。次の XML スキーマでは、バイト型で NULL にできる <root> 要素を定義しています。

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

次のクエリでは、式により単一のバイト型が返されるので、instance of から True が返されます。

DECLARE @var XML(SC)
SET @var = '<root>111</root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO

<root> 要素を NULL にすると、その要素の値は空のシーケンスになります。つまり、式 /root[1] から空のシーケンスが返されます。したがって、instance of xs:byte では False が返されます。この場合の既定の基数は 1 であることに注意してください。

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO
-- result = false

出現インジケータ (?) を追加して基数を指定すると、シーケンス式から True が返されます。

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte? ') 
GO
-- result = true

シーケンス型の式のテストは、次の 2 段階で完了することに注意してください。

  1. 最初に、式の型が指定された型と一致するかどうかがテストで判断されます。
  2. 次に、型が一致した場合は、式から返されたアイテム数が指定された出現インジケータと一致するかどうかが判断されます。

どちらにも該当する場合、instance of 式から True が返されます。

例 D

次の例では、AdventureWorks データベースの xml 型の Instructions 列に対してクエリを指定しています。Instructions 列にはスキーマが関連付けられているので、この列は型指定された XML 列です。詳細については、「AdventureWorks データベースの xml データ型表現」を参照してください。XML スキーマで整数型の LocationID 属性が定義されます。したがって、シーケンス式では instance of xs:integer? から True が返されます。

SELECT Instructions.query(' 
declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
data(/AWMI:root[1]/AWMI:Location[1]/@LocationID) instance of xs:integer?') as Result 
FROM Production.ProductModel 
WHERE ProductModelID = 7

式から返されるノードの型の比較

式からノードのシーケンスが返される場合、シーケンス内のノードの型を確認することが必要な場合があります。次の例は、シーケンス型の構文を使用して、式から返されるノードの型を評価する方法を示しています。次のシーケンス型を使用できます。

  • item() – シーケンスのすべてのアイテムを照合します。
  • node() – シーケンスがノードかどうかを判断します。
  • processing-instruction() – 式から処理命令が返されるかどうかを判断します。
  • comment() – 式からコメントが返されるかどうかを判断します。
  • document-node() – 式からドキュメント ノードが返されるかどうかを判断します。

次の例は、これらのシーケンス型を示しています。

例 A

この例では、型指定されていない XML 変数に対して複数のクエリを実行しています。これらのクエリは、シーケンス型の使用方法を示しています。

DECLARE @var XML
SET @var = '<?xml-stylesheet href="someValue" type="text/xsl" ?>
<root>text node
  <!-- comment 1 --> 
  <a>Data a</a>
  <!-- comment  2 -->
</root>'

最初のクエリでは、式から要素 <a> の型指定された値が返されます。2 つ目のクエリでは、式から要素 <a> が返されます。これらはどちらもアイテムです。したがって、両方のクエリから True が返されます。

SELECT @var.query('data(/root[1]/a[1]) instance of item()')
SELECT @var.query('/root[1]/a[1] instance of item()')

次の 3 つのクエリのすべての XQuery 式では、<root> 要素の要素ノードの子が返されます。そのため、シーケンス型の式 instance of node() から True が返され、他の 2 つの式 instance of text()instance of document-node() からは False が返されます。

SELECT @var.query('(/root/*)[1] instance of node()')
SELECT @var.query('(/root/*)[1] instance of text()')
SELECT @var.query('(/root/*)[1] instance of document-node()') 

次のクエリでは、<root> 要素の親はドキュメント ノードなので、instance of document-node() 式から True が返されます。

SELECT @var.query('(/root/..)[1] instance of document-node()') -- true

次のクエリでは、式から XML インスタンスの最初のノードを取得します。このノードは処理命令ノードなので、instance of processing-instruction() 式により True が返されます。

SELECT @var.query('(/node())[1] instance of processing-instruction()')

実装の制限事項

次に、特定の制限事項を示します。

  • コンテンツ型の構文で document-node() を使用することはできません。
  • processing-instruction(name) 構文はサポートされません。

要素のテスト

要素のテストは、式から返された要素ノードと特定の名前や型を持つ要素ノードを照合する場合に使用します。次のような要素のテストを使用できます。

element ()
element(ElementName)
element(ElementName, ElementType?) 
element(*, ElementType?)

属性のテスト

属性のテストでは、式から返された属性が属性ノードであるかどうかが判断されます。次のような属性のテストを使用できます。

attribute()

attribute(AttributeName)

attribute(AttributeName, AttributeType)

テストの例

次の例は、要素のテストおよび属性のテストが役立つシナリオを示しています。

例 A

次の XML スキーマでは、<firstName> 要素と <lastName> 要素を省略できる、CustomerType 複合型を定義しています。指定した XML インスタンスでは、特定の顧客の名前が存在するかどうかを判断する必要があるとします。

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="myNS" xmlns:ns="myNS">
  <complexType name="CustomerType">
     <sequence>
        <element name="firstName" type="string" minOccurs="0" 
                  nillable="true" />
        <element name="lastName" type="string" minOccurs="0"/>
     </sequence>
  </complexType>
  <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO
DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS">
<firstName>SomeFirstName</firstName>
<lastName>SomeLastName</lastName>
</x:customer>'

次のクエリでは、instance of element (firstName) 式を使用して、<customer> の最初の子要素が <firstName> という名前の要素であるかどうかを判断しています。この場合、True が返されます。

SELECT @var.query('declare namespace x="myNS"; 
     (/x:customer/*)[1] instance of element (firstName)')
GO

インスタンスから <firstName> 要素を削除すると、クエリにより False が返されます。

また、次の構文も使用できます。

  • 次のクエリで示すような element(ElementName, ElementType?) シーケンス型の構文。この構文では、名前が firstName で型が xs:string の NULL 要素ノードまたは NULL 以外の要素ノードが照合されます。

    SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer/*)[1] instance of element (firstName, xs:string?)')
    
  • 次のクエリで示すような element(*, type?) シーケンス型の構文。この構文では、名前に関係なく、要素ノードの型が xs:string の場合にその要素ノードが照合されます。

    SELECT @var.query('declare namespace x="myNS"; (/x:customer/*)[1] instance of element (*, xs:string?)')
    GO
    

例 B

次の例は、式から返されたノードが特定の名前の要素ノードかどうかを判断する方法を示しています。この例では、element() テストを使用しています。

次の例では、クエリ対象の XML インスタンス内にある 2 つの <Customer> 要素の型は、それぞれ CustomerTypeSpecialCustomerType という異なる型です。式から返される <Customer> 要素の型を確認するとします。次の XML スキーマ コレクションでは、CustomerType 型と SpecialCustomerType 型を定義しています。

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
          targetNamespace="myNS"  xmlns:ns="myNS">
  <complexType name="CustomerType">
    <sequence>
      <element name="firstName" type="string"/>
      <element name="lastName" type="string"/>
    </sequence>
  </complexType>
  <complexType name="SpecialCustomerType">
     <complexContent>
       <extension base="ns:CustomerType">
        <sequence>
            <element name="Age" type="int"/>
        </sequence>
       </extension>
     </complexContent>
    </complexType>
   <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

この XML スキーマ コレクションは、型指定された xml 変数を作成する場合に使用します。この変数に割り当てられた XML インスタンスには、型が異なる 2 つの <customer> 要素があります。最初の要素は CustomerType 型で、2 つ目の要素は SpecialCustomerType 型です。

DECLARE @var XML(SC)
SET @var = '
<x:customer xmlns:x="myNS">
   <firstName>FirstName1</firstName>
   <lastName>LastName1</lastName>
</x:customer>
<x:customer xsi:type="x:SpecialCustomerType" xmlns:x="myNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <firstName> FirstName2</firstName>
   <lastName> LastName2</lastName>
   <Age>21</Age>
</x:customer>'

次のクエリで、instance of element (*, x:SpecialCustomerType ?) 式は False を返します。この式で返されている最初の customer 要素が、SpecialCustomerType 型ではないためです。

SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer)[1] instance of element (*, x:SpecialCustomerType ?)')

上記のクエリの式を変更し、2 つ目の <customer> 要素 (/x:customer)[2]) を取得すると、instance of から True が返されます。

例 C

この例では、属性のテストを使用します。次の XML スキーマでは、CustomerID 属性と Age 属性を含む CustomerType 複合型を定義しています。Age 属性は省略できます。特定の XML インスタンスでは、<customer> 要素内に Age 属性が指定されているかどうかを判断できます。

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
       targetNamespace="myNS" xmlns:ns="myNS">
<complexType name="CustomerType">
  <sequence>
     <element name="firstName" type="string" minOccurs="0" 
               nillable="true" />
     <element name="lastName" type="string" minOccurs="0"/>
  </sequence>
  <attribute name="CustomerID" type="integer" use="required" />
  <attribute name="Age" type="integer" use="optional" />
 </complexType>
 <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

次のクエリでは、クエリ対象の XML インスタンスに Age という名前の属性ノードが存在するので、True が返されます。この式では、attribute(Age) 属性のテストを使用しています。属性の順序が決まっていないので、クエリでは FLWOR 式を使用してすべての属性を取得し、instance of 式を使用して各属性をテストします。この式では、最初に、型指定された xml 変数を作成するために XML スキーマ コレクションが作成されます。

DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS" CustomerID="1" Age="22" >
<firstName>SomeFName</firstName>
<lastName>SomeLName</lastName>
</x:customer>'
SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age)) THEN
        "true"
        ELSE
        ()')   
GO

省略可能な Age 属性をインスタンスから削除すると、上記のクエリにより False が返されます。

属性のテストで、属性の名前と型 (attribute(name,type)) を指定できます。

SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age, xs:integer)) THEN
        "true"
        ELSE
        ()')

また、 attribute(*, type) シーケンス型の構文を指定することもできます。この構文を指定すると、名前は一致しなくても属性の型と指定した型が一致する場合に属性のノードが照合されます。

実装の制限事項

次に、特定の制限事項を示します。

  • 要素のテストでは、型名の後に出現インジケータ (?) を指定する必要があります。
  • element(ElementName, TypeName) はサポートされません。
  • element(*, TypeName) はサポートされません。
  • schema-element() はサポートされません。
  • schema-attribute(AttributeName) はサポートされません。
  • xsi:type または xsi:nil に対する明示的なクエリの実行はサポートされません。

参照

概念

SequenceType 式 (XQuery)
XQuery の基礎

その他の技術情報

SQL Server Profiler の使用

ヘルプおよび情報

SQL Server 2005 の参考資料の入手