次の方法で共有


パス式 - 述語の指定

適用対象: SQL Server

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

省略可能な述語は、パス式の軸ステップの 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 ノード内の最初の <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 インスタンスを保持する xmltype 変数 (顧客アンケート 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 番目のステップは述語を指定します。 この述語の値はブール型の値です。 この値が 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 に減らします。