共用方式為


路徑運算式 - 指定述詞

適用於:SQL Server

如主題 :XQuery 中的路徑運算式,路徑運算式中的軸步驟包含下列元件:

  • 節點測試。 如需詳細資訊,請參閱 在路徑運算式步驟 中指定節點測試。

  • 零個或多個述詞。 這是選擇性。

選擇性述詞是路徑運算式中座標軸步驟的第三個部分。

述詞

述詞是用來套用指定的測試來篩選節點序列。 述詞運算式會以方括弧括住,並系結至路徑運算式中的最後一個節點。

例如,假設已宣告 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] 的有效運算式:

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>  

不過,第二個路徑運算式會選取第一個 /People/Person 節點下的所有 <Name> 元素。 因此,它會傳回下列專案:

<Name>John</Name>  

括弧也可以用來變更述詞的評估順序。 例如,在下列運算式中,會使用一組括弧來分隔述詞 [1]:

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 之序列中的節點。 所有其他節點都會捨棄。

例如,下列路徑運算式在其第二個步驟中包含述詞:

/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  
    

    此查詢中的路徑運算式只會 <Location> 傳回已指定 LotSize 屬性的專案節點。 如果述詞傳回特定 <Location> 的空序列,則結果中不會傳回該工作中心位置。

  2. 述詞值只能是 xs:integer、xs:Boolean 或 node*。 對於 node*,如果有任何節點,述詞會評估為 True,而空白序列則為 False。 任何其他數數值型別,例如 double 和 float 類型,都會產生靜態類型錯誤。 如果產生的整數等於內容位置的值,則運算式的述詞真值為 True。 此外,只有整數常值和 last() 函式會將篩選步驟運算式的基數減少為 1。

    例如,下列查詢會擷取 元素的第三個 <Features> 子項目節點。

    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 的節點,這個運算式的述詞真值才為 True。

    • 第三個步驟也會指定萬用字元 \ ,指出節點測試中的所有節點。 不過,述詞會篩選節點,只傳回第三個位置中的節點。

    • 查詢會傳回檔根項目子系之元素子 ProductDescription>< 系的第三個子項目節點。 <Features>

  3. 如果述詞運算式的值是布林值類型的一個簡單類型值,述詞真值會等於述詞運算式的值。

    例如,下列查詢是針對 保存 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 迴圈中的 運算式有兩個步驟,而第二個步驟則指定述詞。 這個述詞的值是布林型別值。 如果此值為 True,述詞的真值也是 True。

    • 此查詢會傳 <Customer> 回檔根目錄之 Survey > 元素子系的元素子系,其述詞值為 True。 < 以下是結果:

      <CustomerWithChildren CustomerID="1"/>   
      
  4. 如果述詞運算式的值是包含至少一個節點的序列,述詞真值就是 True。

例如,下列查詢會從與 wm 前置詞相關聯的命名空間擷取產品模型的 ProductModelID,其 XML 類別目錄描述至少包含一項功能、元素的 ><Features 子項目。

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() 方法內的 路徑運算式會在第二個步驟中指定述詞。 如果述詞運算式傳回至少一個特徵的序列,則這個述詞運算式的真值為 True。 在此情況下,因為 exist() 方法會傳回 True,因此會傳回 ProductModelID。

靜態類型與述詞篩選準則

述詞也可能會影響運算式的靜態推斷類型。 整數常值和 last() 函式最多會將篩選步驟運算式的基數減少為一個。