次の方法で共有


パス式のステップでの述語の指定

パス式 (XQuery)」で説明されているように、パス式の軸ステップには、次のコンポーネントが含まれています。

省略可能な述語は、パス式の軸ステップの 3 番目の要素です。

述語

述語は、指定されたテストを適用して、ノード シーケンスをフィルター処理するために使用されます。 述語式は、角かっこで囲み、パス式の最後のノードにバインドされます。

たとえば、次に示すように、xml データ型の SQL パラメーター値 (x) が宣言されているとします。

declare @x xml
set @x = '
<People>
  <Person>
    <Name>John</Name>
    <Age>24</Age>
  </Person>
  <Person>
    <Name>Goofy</Name>
    <Age>54</Age>
  </Person>
  <Person>
    <Name>Daffy</Name>
    <Age>30</Age>
  </Person>
</People>
'

この場合、次の式は、述語の値 [1] が 3 つの異なるノード レベルで使用されていますが、いずれも有効です。

select @x.query('/People/Person/Name[1]')
select @x.query('/People/Person[1]/Name')
select @x.query('/People[1]/Person/Name')

どの式でも、述語は適用対象のパス式のノードにバインドされていることに注意してください。 たとえば、最初のパス式は、各 /People/Person ノード内の 1 つ目の <Name> 要素と、指定された XML インスタンスを選択し、次の結果を返します。

<Name>John</Name><Name>Goofy</Name><Name>Daffy</Name>

ただし、2 番目のパス式は、最初の /People/Person ノードの下にあるすべての <Name> 要素を選択します。 したがって、次の結果を返します。

<Name>John</Name>

また、かっこを使用して、述語の評価の順序を変えることもできます。 たとえば、次の式では、述語 [1] と (/People/Person/Name) というパスを分離するために、かっこが使用されています。

select @x.query('(/People/Person/Name)[1]')

この例では、述語が適用される順序が変わります。 これで、かっこで囲まれたパス (/People/Person/Name) が最初に評価された後に、このパスに一致するすべてのノードを含むセットに述語操作 [1] が適用されます。 かっこがない場合、操作の順序は、最初のパス式の例と同様に [1] が child::Name ノード テストとして適用されるという点で異なります。

量化子と述語

量化子は、述語自体の角かっこ内で、複数回使用および追加できます。 たとえば、前の例を使用すると、次の式は複雑な述語のサブ式内で複数の量化子を使用する有効な式です。

select @x.query('/People/Person[contains(Name[1], "J") and xs:integer(Age[1]) < 40]/Name/text()')

述語式の結果は、ブール値に変換され、述語の真偽値として参照されます。 述語の真偽値が True であるシーケンスのノードのみが、結果として返されます。 それ以外のすべてのノードは破棄されます。

たとえば、次のパス式では、2 番目のステップに述語があります。

/child::root/child::Location[attribute::LocationID=10]

この述語で指定される条件は、すべての <Location> 要素ノードの子に適用されます。 結果として、LocationID 属性値が 10 であるワーク センターの場所のみが返されます。

上記のパス式は、次の SELECT ステートメント内で実行されます。

SELECT Instructions.query('
declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
 /child::AWMI:root/child::AWMI:Location[attribute::LocationID=10]
')
FROM Production.ProductModel
WHERE ProductModelID=7

述語の真偽値の計算

述語の真偽値の判定には、XQuery の仕様に従い、次の規則が適用されます。

  1. 述語式の値が空のシーケンスの場合、述語の真偽値は False になります。

    次に例を示します。

    SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
     /child::AWMI:root/child::AWMI:Location[attribute::LotSize]
    ')
    FROM Production.ProductModel
    WHERE ProductModelID=7
    

    この式のパス式は、LotSize 属性が指定されている <Location> 要素ノードのみを返します。 述語が、ある特定の <Location> に空のシーケンスを返した場合、結果にはこのワーク センターの場所は返されません。

  2. 述語の値には、xs:integer、xs:Boolean、または node* しか使用できません。 node* では、ノードがある場合に述語は True に評価され、空のシーケンスに対しては False になります。 double 型や float 型など、他の数値型では、静的な型指定エラーが生成されます。 式の述語の真偽値は、結果の整数がコンテキストの位置の値と同じ場合にのみ、True になります。 また、整数リテラル値と last() 関数のみが、フィルター処理されたステップ式の基数を 1 にすることができます。

    たとえば、次のクエリは、<Features> 要素の 3 番目の子要素ノードを取得します。

    SELECT CatalogDescription.query('
    declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
    declare namespace wm="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelWarrAndMain";
     /child::PD:ProductDescription/child::PD:Features/child::*[3]
    ')
    FROM Production.ProductModel
    WHERE ProductModelID=19
    

    上のクエリに関して、次の点に注意してください。

    • 式の 3 番目のステップは、値が 3 である述語式を指定しています。 したがって、この式の述語の真偽値は、コンテキストの位置が 3 であるノードに対してのみ True になります。

    • 3 番目のステップには、ノード テストのすべてのノードを意味するワイルドカード文字 (*) も指定されています。 ただし、述語により、ノードがフィルター処理され、3 番目の位置にあるノードのみが返されます。

    • このクエリは、ドキュメント ルートの <ProductDescription> 子要素の <Features> 子要素ノードの 3 番目の子要素ノードを返します。

  3. 述語式の値が Boolean 型の単純なデータ型値である場合、述語の真偽値は、述語式の値と同じになります。

    たとえば、次のクエリは、顧客調査 XML インスタンスという XML インスタンスを保持する xml 型の変数に対して指定されています。 このクエリは、子供がいる顧客を取得します。 このクエリの場合、これは <HasChildren>1</HasChildren> になります。

    declare @x xml
    set @x='
    <Survey>
      <Customer CustomerID="1" >
      <Age>27</Age>
      <Income>20000</Income>
      <HasChildren>1</HasChildren>
      </Customer>
      <Customer CustomerID="2" >
      <Age>27</Age>
      <Income>20000</Income>
      <HasChildren>0</HasChildren>
      </Customer>
    </Survey>
    '
    declare @y xml
    set @y = @x.query('
      for $c in /child::Survey/child::Customer[( child::HasChildren[1] cast as xs:boolean ? )]
      return 
          <CustomerWithChildren>
              { $c/attribute::CustomerID }
          </CustomerWithChildren>
    ')
    select @y
    

    上のクエリに関して、次の点に注意してください。

    • for ループ内の式には 2 つのステップがあり、2 番目のステップに述語が指定されています。 この述語の値は、Boolean 型の値です。 この値が True の場合は、述語の真偽値も True になります。

    • このクエリは、ドキュメント ルートの <Survey> 子要素の <Customer> 子要素で、述語の値が True であるものを返します。 結果を次に示します。

      <CustomerWithChildren CustomerID="1"/> 
      
  4. 述語式の値が少なくとも 1 つのノードを含むシーケンスの場合、述語の真偽値は True になります。

たとえば、次のクエリは、XML カタログの説明に少なくとも 1 つの機能 (<Features> 要素の子要素) が含まれている製品モデルの ProductModelID を wm プレフィックスに関連付けられている名前空間から取得します。

SELECT ProductModelID
FROM   Production.ProductModel
WHERE CatalogDescription.exist('
             declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
             declare namespace wm="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelWarrAndMain";
             /child::PD:ProductDescription/child::PD:Features[wm:*]
             ') = 1

上のクエリに関して、次の点に注意してください。

  • WHERE 句は、exist() メソッド (XML データ型) を指定します。

  • exist() メソッド内のパス式は、2 番目のステップで述語を指定しています。 述語式が少なくとも 1 つの機能のシーケンスを返す場合、この述語式の真偽値は True になります。 この場合、exist() メソッドが True を返すので、ProductModelID が返されます。

静的な型指定フィルターおよび述語フィルター

述語は、静的に推定される式の型にも影響する場合があります。 整数リテラル値と last() 関数では、フィルター処理されたステップ式の基数を最大で 1 に下げることができます。