Общие способы применения запросов XQuery

В этом подразделе приведены примеры использования запросов XQuery.

Примеры

А.Запрос описаний каталога для поиска продукции и значений веса

Следующий запрос возвращает идентификаторы моделей продукции и их вес (если указан) из описания в каталоге продукции. Запрос формирует 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

В предыдущем запросе обратите внимание на следующее.

  • Ключевое слово namespace в прологе запроса XQuery определяет префикс пространства имен, используемый в теле запроса.

  • Текст запроса формирует требуемый XML.

  • В предложении WHERE метод exist() используется для нахождения только тех строк, которые содержат описания каталога продукции. То есть XML-данные, которые содержат элемент <ProductDescription>.

Результат:

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

Следующий запрос получает те же сведения, но лишь для моделей продукции, описания которых в каталоге включают значение веса (элемент <Weight>) в спецификациях (элемент <Specifications>). В данном примере для объявления префикса pd и привязки пространства имен используется предложение WITH XMLNAMESPACES. При таком подходе описание привязки отсутствует как в методе 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

В предыдущем запросе метод exist() типа данных xml в предложении WHERE производит проверку наличия элемента <Weight> в элементе <Specifications>.

Б.Поиск идентификаторов моделей продукции, описания которых в каталоге имеют фронтальные и малоразмерные изображения.

Описание в каталоге продукции формата 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>
...

В.Создание неструктурированного списка пар имен и характеристик моделей продукции, где каждая пара заключена в элемент <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() возвращает все узлы. В их число входят узлы элементов, текстовые узлы, инструкции по обработке, а также примечания.

  • Два контейнера «цикл по элементам» формируют декартов продукт, из которого возвращаются имя продукта и отдельная характеристика.

  • 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 AdventureWorks retail store.</p2:Description>
    </p2:Maintenance>
</Feature>
...
...    

Г.Построение списка, состоящего из имени модели продукции, идентификатора модели и характеристик, сгруппированных в элементе <Product> на основе описания модели продукции в каталоге.

Используя сведения, хранящиеся в описании модели продукции в каталоге, следующий запрос строит список, включающий в себя имя модели продукции, идентификатор модели и характеристики, сгруппированные в элементе <Product>.

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>
   ...

Д.Получение описаний характеристик для модели продукции.

Следующий запрос формирует XML, включающий в себя элемент <Product> с атрибутами ProducModelID и ProductModelName, а также две первые характеристики. Следует уточнить, что первые две характеристики продукта являются первыми двумя дочерними элементами элемента <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() используется для определения положения элементов в последовательности.

Е.Поиск в описании каталога продукции имен элементов, которые заканчиваются на «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>        

Ж.Поиск сводных описаний, содержащих слово «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 определяет методы query() и value() для типа данных xml. Поэтому вместо повторения декларации пространства имен дважды в двух разных прологах запроса, в запросе используется префикс pd, который определяется только один раз в предложении WITH XMLNAMESPACES.

Обратите внимание на следующее в предыдущем запросе.

  • Предложение WHERE используется для получения лишь тех строк, которые содержат слово «Aerodynamic» в элементе <Summary> описания каталога.

  • Функция contains() используется для определения наличия слова в тексте.

  • Метод value() типа данных xml сравнивает возвращенное методом 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>  

З.Поиск моделей продукции, описания которых в каталоге не содержат изображений моделей продукции.

Следующий запрос получает значения ProductModelID моделей продукции, описания которых в каталоге не содержат элемента <Picture>.

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), то в ответ на запрос будет извлечен идентификатор модели продукции. В противном случае идентификатор не извлекается.

  • В данном случае результирующий набор пуст, поскольку все описания продукции содержат элемент <Picture>.

См. также

Справочник

Запросы XQuery, использующие иерархию

Запросы XQuery, использующие упорядочивание

Запросы XQuery, обрабатывающие реляционные данные

Поддержка пространств имен в XQuery

Основные понятия

Поиск строки в XQuery

Добавление пространств имен в запросы с WITH XMLNAMESPACES

XML-данные (SQL Server)

Другие ресурсы

Справочник по языку XQuery (SQL Server)