XQuery 常规使用情况

本主题提供了 XQuery 常规使用情况示例。

示例

A. 查询目录说明以查找产品和权重

下面的查询将从产品目录说明中返回产品型号 ID 和权重(如果它们存在的话)。该查询将构造如下形式的 XML 内容:

<Product ProductModelID="…">
  <Weight>…</Weight>
</Product>

以下是查询语句:

SELECT CatalogDescription.query('
declare namespace p1="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
  <Product  ProductModelID="{ (/p1:ProductDescription/@ProductModelID)[1] }">
     { 
       /p1:ProductDescription/p1:Specifications/Weight 
     } 
  </Product>
') as Result
FROM Production.ProductModel
WHERE CatalogDescription is not null

请注意上述查询的以下方面:

  • XQuery prolog 中的 namespace 关键字用于定义查询主体中所使用的命名空间前缀。

  • 查询主体用于构造所需的 XML。

  • 在 WHERE 子句中,exist() 方法用于只查找那些包含产品目录说明的行。即,包含 <ProductDescription> 元素的 XML。

结果如下:

<Product ProductModelID="19"/>
<Product ProductModelID="23"/> 
<Product ProductModelID="25"/> 
<Product ProductModelID="28"><Weight>Varies with size.</Weight></Product>
<Product ProductModelID="34"/>
<Product ProductModelID="35"/>

下面的查询将检索相同的信息,但是仅限于其目录说明在规范(<Specifications> 元素)中包含权重(<Weight> 元素)的那些产品型号。此示例使用 WITH XMLNAMESPACES 来声明 pd 前缀与其命名空间的绑定。这样一来,该绑定就不在 query() 方法和 exist() 方法中说明。

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS pd)
SELECT CatalogDescription.query('
          <Product  ProductModelID="{ (/pd:ProductDescription/@ProductModelID)[1] }">
                 { 
                      /pd:ProductDescription/pd:Specifications/Weight 
                 } 
          </Product>
') as x
FROM Production.ProductModel
WHERE CatalogDescription.exist('/pd:ProductDescription/pd:Specifications//Weight ') = 1

在上面的查询中,WHERE 子句中的 xml 数据类型的 exist() 方法用于检查 <Specifications> 元素中是否包含 <Weight> 元素。

B. 为其目录说明包含前角和小幅图片的产品型号查找产品型号 ID

XML 产品目录说明包含产品图片(<Picture> 元素)。每个图片都具有若干属性。这些属性包括图片角度(<Angle> 元素)和大小(<Size> 元素)。

对于其目录说明包含前角和小幅图片的产品型号,查询将构造具有以下形式的 XML:

< Product ProductModelID="…">
  <Picture>
    <Angle>front</Angle>
    <Size>small</Size>
  </Picture>
</Product>
WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS pd)
SELECT CatalogDescription.query('
   <pd:Product  ProductModelID="{ (/pd:ProductDescription/@ProductModelID)[1] }">
      <Picture>
         {  /pd:ProductDescription/pd:Picture/pd:Angle } 
         {  /pd:ProductDescription/pd:Picture/pd:Size } 
      </Picture>
   </pd:Product>
') as Result
FROM  Production.ProductModel
WHERE CatalogDescription.exist('/pd:ProductDescription/pd:Picture') = 1
AND   CatalogDescription.value('(/pd:ProductDescription/pd:Picture/pd:Angle)[1]', 'varchar(20)')  = 'front'
AND   CatalogDescription.value('(/pd:ProductDescription/pd:Picture/pd:Size)[1]', 'varchar(20)')  = 'small'

请注意上述查询的以下方面:

  • 在 WHERE 子句中,exist() 方法用于只检索那些包含含有 <Picture> 元素的产品目录说明的行。

  • WHERE 子句通过两次使用 value() 方法来比较 <Size> 元素和 <Angle> 元素的值。

下面是部分结果:

<p1:Product 
  xmlns:p1="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription" 
  ProductModelID="19">
  <Picture>
    <p1:Angle>front</p1:Angle>
    <p1:Size>small</p1:Size>
  </Picture>
</p1:Product>
...

C. 创建一个由产品型号名称/功能对组成的平面列表,每个对都包含在 <Features> 元素中

在产品型号目录说明中,XML 包含若干种产品功能。所有这些功能都包含在 <Features> 元素中。查询将使用 XML 构造 (XQuery) 来构造所需的 XML。大括号中的表达式将替换为结果。

SELECT CatalogDescription.query('
declare namespace p1="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
  for $pd in /p1:ProductDescription,
   $f in $pd/p1:Features/*
  return
   <Feature>
     <ProductModelName> { data($pd/@ProductModelName) } </ProductModelName>
     { $f }
  </Feature>        
') as x
FROM Production.ProductModel
WHERE ProductModelID=19

请注意上述查询的以下方面:

  • $pd/p1:Features/* 只返回 <Features> 的元素节点子级,但 $pd/p1:Features/node() 将返回所有节点。其中包括元素节点、文本节点、处理指令和注释。

  • 两个 FOR 循环将生成笛卡儿积,将从该积返回产品名称和单个功能。

  • ProductName 是一个属性。此查询中的 XML 构造将其作为一个元素返回。

下面是部分结果:

<Feature>
 <ProductModelName>Mountain 100</ProductModelName>
 <ProductModelID>19</ProductModelID>
 <p1:Warranty 
   xmlns:p1="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelWarrAndMain">
    <p1:WarrantyPeriod>3 year</p1:WarrantyPeriod>
    <p1:Description>parts and labor</p1:Description>
 </p1:Warranty>
</Feature>
<Feature>
 <ProductModelName>Mountain 100</ProductModelName>
 <ProductModelID>19</ProductModelID>
 <p2:Maintenance xmlns:p2="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelWarrAndMain">
    <p2:NoOfYears>10</p2:NoOfYears>
    <p2:Description>maintenance contact available through your dealer 
           or any Adventure Works retail store.</p2:Description>
    </p2:Maintenance>
</Feature>
...
...    

D. 从产品型号的目录说明中列出在 <Product> 元素内进行分组的产品型号名称、产品型号 ID 以及产品功能

使用产品型号目录说明中存储的信息,下面的查询列出了在 <Product> 元素内进行分组的产品型号名称、产品型号 ID 以及产品功能。

SELECT ProductModelID, CatalogDescription.query('
     declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     <Product>
         <ProductModelName> 
           { data(/pd:ProductDescription/@ProductModelName) } 
         </ProductModelName>
         <ProductModelID> 
           { data(/pd:ProductDescription/@ProductModelID) } 
         </ProductModelID>
         { /pd:ProductDescription/pd:Features/* }
     </Product>        
') as x
FROM Production.ProductModel
WHERE ProductModelID=19

下面是部分结果:

<Product>
  <ProductModelName>Mountain 100</ProductModelName>
  <ProductModelID>19</ProductModelID>
  <p1:Warranty>... </p1:Warranty>
  <p2:Maintenance>...  </p2:Maintenance>
  <p3:wheel xmlns:p3="https://www.adventure-works.com/schemas/OtherFeatures">High performance wheels.</p3:wheel>
  <p4:saddle xmlns:p4="https://www.adventure-works.com/schemas/OtherFeatures">
    <p5:i xmlns:p5="http://www.w3.org/1999/xhtml">Anatomic design</p5:i> and made from durable leather for a full-day of riding in comfort.</p4:saddle>
  <p6:pedal xmlns:p6="https://www.adventure-works.com/schemas/OtherFeatures">
    <p7:b xmlns:p7="http://www.w3.org/1999/xhtml">Top-of-the-line</p7:b> clipless pedals with adjustable tension.</p6:pedal>
   ...

E. 检索产品型号功能说明

下面的查询将构造包含 <Product> 元素(具有 ProducModelIDProductModelName 属性)以及前两个产品功能的 XML。前两个产品功能特指 <Features> 元素的前两个子元素。如果有更多的功能,此查询将返回空的 <There-is-more/> 元素。

SELECT CatalogDescription.query('
declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     <Product> 
          { /pd:ProductDescription/@ProductModelID }
          { /pd:ProductDescription/@ProductModelName } 
          {
            for $f in /pd:ProductDescription/pd:Features/*[position()<=2]
            return
            $f 
          }
          {
            if (count(/pd:ProductDescription/pd:Features/*) > 2)
            then <there-is-more/>
            else ()
          } 
     </Product>        
') as Result
FROM Production.ProductModel
WHERE CatalogDescription is not NULL

请注意上述查询的以下方面:

  • FOR ... RETURN 循环结构用于检索前两个产品功能。position() 函数用于查找元素在序列中的位置。

F. 从产品目录说明中查找以“ons”结尾的元素名称

下面的查询将搜索目录说明并返回 <ProductDescription> 元素中其名称以“ons”结尾的所有元素。

SELECT ProductModelID, CatalogDescription.query('
     declare namespace p1="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
      for $pd in /p1:ProductDescription/*[substring(local-name(.),string-length(local-name(.))-2,3)="ons"]
      return 
          <Root>
             { $pd }
          </Root>
') as Result
FROM Production.ProductModel
WHERE CatalogDescription is not NULL

下面是部分结果:

ProductModelID   Result
-----------------------------------------
         19        <Root>       
                     <p1:Specifications xmlns:p1="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription">        
                          ...       
                     </p1:Specifications>       
                   </Root>        

G. 查找包含单词“Aerodynamic”的概要说明

下面的查询将检索其目录说明在概要说明中包含单词“Aerodynamic”的产品型号:

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS pd)
SELECT ProductModelID, CatalogDescription.query('
          <Prod >
             { /pd:ProductDescription/@ProductModelID }
             { /pd:ProductDescription/pd:Summary }
          </Prod>
 ') as Result
FROM Production.ProductModel
WHERE CatalogDescription.value('
     contains( string( (/pd:ProductDescription/pd:Summary)[1] ),"Aerodynamic")','bit') = 1

请注意,SELECT 查询指定了 xml 数据类型的 query() 方法和 value() 方法。因此,该查询中使用了前缀 pd,并且只使用 WITH XMLNAMESPACES 定义了一次该前缀 pd,而不是在两个不同的查询 prolog 中两次重复声明命名空间。

请注意上述查询的以下方面:

  • WHERE 子句用于只检索其目录说明在 <Summary> 元素中包含单词“Aerodynamic”的行。

  • contains() 函数用于查看文本中是否包含该单词。

  • xml 数据类型的 value() 方法用于将 contains() 返回的值与 1 进行比较。

结果如下:

ProductModelID Result      
-------------- ------------------------------------------
28     <Prod ProductModelID="28">
        <pd:Summary xmlns:pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription">
       <p1:p xmlns:p1="http://www.w3.org/1999/xhtml">
         A TRUE multi-sport bike that offers streamlined riding and a
         revolutionary design. Aerodynamic design lets you ride with the 
         pros, and the gearing will conquer hilly roads.</p1:p>
       </pd:Summary>
      </Prod>  

H. 查找其目录说明不包含产品型号图片的产品型号

下面的查询将检索其目录说明不包含 <Picture> 元素的产品型号的 ProductModelID。

SELECT  ProductModelID
FROM    Production.ProductModel
WHERE   CatalogDescription is not NULL
AND     CatalogDescription.exist('declare namespace p1="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     /p1:ProductDescription/p1:Picture
') = 0

请注意上述查询的以下方面:

  • 如果 WHERE 子句中的 exist() 方法返回 False (0),则将返回产品型号 ID。否则,将不返回。

  • 由于所有产品说明都包含 <Picture> 元素,因此在这种情况下结果集为空。