涉及层次结构的 XQuery

AdventureWorks2008R2 数据库中的大多数 xml 类型列是半结构化文档。因此,每行中存储的文档可能看起来不同。本主题中的查询示例说明如何从这些不同的文档提取信息。

示例

A. 从生产说明文档检索生产车间以及这些生产车间的第一个生产步骤

对于产品型号 7,查询构造了包括下列内容的 XML:具有 ProductModelIDProductModelName 属性的 <ManuInstr> 元素,以及一个或多个 <Location> 子元素。

每个 <Location> 元素具有它自己的属性集和一个 <step> 子元素。此 <step> 子元素是生产车间的第一个生产步骤。

SELECT Instructions.query('
     declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   <ManuInstr  ProdModelID = "{sql:column("Production.ProductModel.ProductModelID") }" 
                ProductModelName = "{ sql:column("Production.ProductModel.Name") }" >
            { 
              for $wc in //AWMI:root/AWMI:Location
              return
                <Location>
                 {$wc/@* }
                 <step1> { string( ($wc//AWMI:step)[1] ) } </step1>
                </Location>
            }
          </ManuInstr>
') as Result
FROM Production.ProductModel
WHERE ProductModelID=7;

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

  • XQuery Prolog 中的 namespace 关键字定义命名空间前缀。随后,将在查询正文中使用此前缀。

  • 上下文切换标记 {) 和 (} 用于将查询从 XML 构造切换到查询计算。

  • sql:column() 用于在正构建的 XML 中包括关系值。

  • 在构造 <Location> 元素时,$wc/@* 将检索所有生产车间属性。

  • string() 函数返回 <step> 元素的字符串值。

下面是部分结果:

<ManuInstr ProdModelID="7" ProductModelName="HL Touring Frame">
   <Location LocationID="10" SetupHours="0.5" 
            MachineHours="3" LaborHours="2.5" LotSize="100">
     <step1>Insert aluminum sheet MS-2341 into the T-85A 
             framing tool.</step1>
   </Location>
   <Location LocationID="20" SetupHours="0.15" 
            MachineHours="2" LaborHours="1.75" LotSize="1">
      <step1>Assemble all frame components following 
             blueprint 1299.</step1>
   </Location>
...
</ManuInstr> 

B. 在 AdditionalContactInfo 列中查找所有电话号码

下面的查询通过在整个层次结构中搜索 <telephoneNumber> 元素来检索用于联系特定客户的附加电话号码。因为 <telephoneNumber> 元素可以出现在层次结构中任何位置,所以该查询在搜索中使用后代和自身运算符 (//)。

SELECT AdditionalContactInfo.query('
 declare namespace ci="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactInfo";
 declare namespace act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes";
for $ph in /ci:AdditionalContactInfo//act:telephoneNumber
   return
      $ph/act:number
') as x
FROM  Person.Person
WHERE BusinessEntityID = 291;

结果如下:

<act:number 
  xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
  425-555-1112
</act:number>
<act:number 
  xmlns:act="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ContactTypes">
  425-555-1111
</act:number>

若要只检索顶级电话号码(即 <AdditionalContactInfo> 的 <telephoneNumber> 子元素),查询中的 FOR 表达式应变为

for $ph in /ci:AdditionalContactInfo/act:telephoneNumber.