Поделиться через


Система типов (XQuery)

XQuery является строго типизированным языком для типов схемы и слабо типизированным языком для нетипизированных данных. Ниже приведены предопределенные типы данных языка XQuery:

В этом разделе также описано следующее:

  • Сравнение типизированных и строковых значений узла.
  • Функции data (XQuery) и string (XQuery).
  • Сопоставление типов последовательности, возвращаемой выражением.

Встроенные типы XML-схемы

Встроенные типы XML-схемы обозначаются в пространстве имен префиксом xs. Вот некоторые из этих типов: xs:integer и xs:string. Поддерживаются все встроенные типы данных. Эти типы могут быть использованы при создании коллекции XML-схем.

При обращении к типизированному XML статические и динамические типы узлов определяются коллекцией XML-схем, связанной со столбцом, к которому происходит обращение. Дополнительные сведения о статических и динамических типах см. в разделе Контекст выражения и вычисление запросов (XQuery). Например, представленный ниже запрос указывается по отношению к типизированному столбцу xml (Instructions). В выражении instance of используется для проверки того, что типизированное значение возвращенного атрибута LotSize имеет тип данных xs:decimal.

SELECT Instructions.query('
   DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   data(/AWMI:root[1]/AWMI:Location[@LocationID=10][1]/@LotSize)[1] instance of xs:decimal
') AS Result
FROM Production.ProductModel
WHERE ProductModelID=7

Эти типизированные данные предоставляются коллекцией XML-схем, связанной с указанным столбцом. Дополнительные сведения см. в разделе Представление типов xml-данных в базе данных AdventureWorks.

Типы, определенные в пространстве имен типов данных XPath

Типы, определенные в пространстве имен http://www.w3.org/2004/07/xpath-datatypes обозначаются предопределенным префиксом xdt. Эти типы обладают следующими свойствами:

  • Они не могут использоваться при создании коллекции XML-схем. Эти типы используются системой типов языка XQuery для статического определения типов. Данные могут быть приведены к атомарным типам, например к типу xdt:untypedAtomic в пространстве имен xdt.
  • При обращении к нетипизированным XML статическим и динамическим типом узловых элементов является xdt:untyped, а значения атрибутов имеют тип xdt:untypedAtomic. Результатом выполнения метода query() являются нетипизированные XML. Это означает, что XML-узлы возвращаются в формате xdt:untyped и xdt:untypedAtomic соответственно.
  • Типы xdt:dayTimeDuration и xdt:yearMonthDuration не поддерживаются.

В следующем примере запрос задается на нетипизированной переменной XML. Выражение data(/a[1]) возвращает последовательность атомарных значений. Функция data() возвращает типизированное значение элемента <a>. Так как запрашиваемые XML не типизированы, возвращенное значение имеет тип xdt:untypedAtomic. Следовательно, выражение instance of возвращает значение True.

DECLARE @x xml
SET @x='<a>20</a>'
SELECT @x.query( 'data(/a[1]) instance of xdt:untypedAtomic' )

Вместо извлечения типизированного значения выражение (/a[1]) в следующем примере возвращает последовательность, состоящую из одного элемента <a>. Выражение instance of использует проверку элементов для контроля того, что возвращаемое выражением значение является элементом узла типа xdt:untyped type.

DECLARE @x xml
SET @x='<a>20</a>'
-- Is this an element node whose name is "a" and type is xdt:untyped.
SELECT @x.query( '/a[1] instance of element(a, xdt:untyped?)')
-- Is this an element node of type xdt:untyped.
SELECT @x.query( '/a[1] instance of element(*, xdt:untyped?)')
-- Is this an element node?
SELECT @x.query( '/a[1] instance of element()')
ms177483.note(ru-ru,SQL.90).gifПримечание.
Если при обращении к типизированным XML-экземплярам в выражении запроса содержится родительская ось, сведения о статических типах результирующих узлов становятся недоступными. Однако динамические типы все равно остаются связанными с узлами.

Сравнение типизированных и строковых значений

Каждый узел содержит типизированное и строковое значение. Для типизированных XML-данных тип значения определяется коллекцией XML-схем, связанной со столбцом или переменной, к которым происходит обращение. Для нетипизированных XML-данных возвращенное значение имеет тип xdt:untypedAtomic.

Для извлечения значения узла можно использовать функции data() или string():

  • Функция data возвращает типизированное значение узла.
  • Функция string возвращает строковое значение узла.

В представленной ниже коллекции XML-схем определяется целочисленный элемент <root>:

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" type="integer"/>
</schema>'
GO

В следующем примере выражение вначале извлекает типизированное значение /root[1], а затем добавляет к нему 3.

DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('data(/root[1]) + 3')

В следующем примере выражение завершается ошибкой, так как функция string(/root[1]) возвращает значение строкового типа. Затем указанное значение передается арифметическому оператору, который может работать только с числовыми операндами.

-- Fails because the argument is string type (must be numeric primitive type).
DECLARE @x xml(SC)
SET @x='<root>5</root>'
SELECT @x.query('string(/root[1]) + 3')

В следующем примере производится вычисление общей суммы атрибутов LaborHours. Функция data() извлекает типизированные значения атрибутов LaborHours из всех элементов <Location> модели продукта. Согласно XML-схеме, связанной со столбцом Instruction, атрибут LaborHours имеет тип данных xs:decimal.

SELECT Instructions.query(' 
DECLARE namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
             sum(data(//AWMI:Location/@LaborHours)) 
') AS Result 
FROM Production.ProductModel 
WHERE ProductModelID=7

Этот запрос возвращает значение 12,75.

ms177483.note(ru-ru,SQL.90).gifПримечание.
Функция data() явно используется в данном запросе только в качестве учебного примера. Если не указано специально, функция sum() неявно применяет функцию data() для извлечения типизированных значений узлов.

Сопоставление типов последовательности

Значением выражения языка XQuery всегда является последовательность из нуля или более элементов. Элемент может быть атомарным значением или узлом. Тип элементов последовательности соответствует типу результатов, возвращаемых выражением запроса. Например:

  • Если значение выражения является атомарным, может понадобиться выяснить, имеет ли оно тип integer, decimal или string.
  • Если значение выражения является XML-узлом, может понадобиться выяснить, является ли оно комментарием, инструкцией по обработке или текстовым узлом.
  • Может возникнуть необходимость выяснить, является ли результат выражения XML-элементом или узлом атрибута с заданным именем и типом.

Для сопоставления типов элементов последовательности можно использовать логический оператор instance of. Дополнительные сведения о выражении instance of см. в разделе Выражения SequenceType (XQuery).

Сравнение типов атомарных значений, возвращенных выражением

Определить тип значения в последовательности может понадобиться в том случае, если выражение возвращает последовательность атомарных значений. В следующем примере показано использование синтаксиса типа последовательности для определения типа атомарного значения, возвращаемого выражением.

Пример A

Тип последовательности empty() может быть использован в выражении для выяснения, является ли полученная последовательность пустой.

В следующем примере XML-схема допускает возможность того, что элемент <root> пуст:

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

Теперь, если типизированный XML-экземпляр указывает значение элемента <root>, выражение instance of empty() возвращает значение False.

DECLARE @var XML(SC1)
SET @var = '<root>1</root>'
-- The following returns False
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

Если в экземпляре элемент <root> пуст, его значением является пустая последовательность, а выражение instance of empty() возвращает значение True.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />'
SELECT @var.query('data(/root[1]) instance of  empty() ')
GO

Пример Б

Иногда требуется выяснить тип последовательности, возвращаемой выражением, до начала обработки. Например, узел может быть определен в XML-схеме с типом union. В следующем примере XML-схема в коллекции определяет атрибут a как имеющий объединенный тип данных, значение которого может иметь десятичный или строковый тип данных.

-- Drop schema collection if it exists.
-- DROP XML SCHEMA COLLECTION SC.
-- GO
CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
  <element name="root">
    <complexType>
       <sequence/>
         <attribute name="a">
            <simpleType>
               <union memberTypes="decimal string"/>
            </simpleType>
         </attribute>
     </complexType>
  </element>
</schema>'
GO

Перед обработкой типизированного XML-экземпляра может понадобиться определить тип данных значения атрибута a. В следующем примере значение атрибута a имеет десятичный тип данных. Следовательно, выражение , instance of xs:decimal возвращает True.

DECLARE @var XML(SC)
SET @var = '<root a="2.5"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:decimal')
GO

Теперь изменим тип значения атрибута a на строковый. Выражение instance of xs:string возвратит значение True.

DECLARE @var XML(SC)
SET @var = '<root a="Hello"/>'
SELECT @var.query('data((/root/@a)[1]) instance of xs:string')
GO

Пример В

В данном примере показывается влияние количества элементов в выражении последовательности. В представленной ниже XML-схеме определяется элемент <root> типа byte, который может быть пустым.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="root" nillable="true" type="byte"/>
</schema>'
GO

В следующем примере выражение instance of возвращает значение True, так как результатом выполнения выражения является одиночный элемент типа byte.

DECLARE @var XML(SC)
SET @var = '<root>111</root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO

При очистке элемента <root> его значением станет пустая последовательность. Поэтому выражение /root[1] возвращает пустую последовательность. Следовательно, выражение instance of xs:byte возвращает значение False. Обратите внимание, что количество элементов по умолчанию в данном случае равно 1.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte ') 
GO
-- result = false

Если количество элементов указывается с добавлением признака вхождения (?), выражение последовательности возвращает значение True.

DECLARE @var XML(SC)
SET @var = '<root xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></root>'
SELECT @var.query('data(/root[1]) instance of  xs:byte? ') 
GO
-- result = true

Обратите внимание, что проверка типа в выражении последовательности проходит в два этапа:

  1. Вначале определяется, совпадает ли тип выражения с указанным типом.
  2. При совпадении типов выражений производится проверка совпадения количества возвращенных выражением элементов с указанным значением признака вхождения.

Если обе проверки дают положительные результаты, выражение instance of возвращает значение True.

Пример Г

В следующем примере запрос обращается к столбцу Instructions, имеющему тип xml и размещающемуся в базе данных AdventureWorks. Это типизированный XML-столбец, так как имеется связанная с ним схема. Дополнительные сведения см. в разделе Представление типов xml-данных в базе данных AdventureWorks. XML-схема определяет целочисленный атрибут LocationID. Поэтому выражение instance of xs:integer? в выражении последовательности возвращает значение True.

SELECT Instructions.query(' 
declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"; 
data(/AWMI:root[1]/AWMI:Location[1]/@LocationID) instance of xs:integer?') as Result 
FROM Production.ProductModel 
WHERE ProductModelID = 7

Сравнение типов узлов, возвращаемых выражением

Определить тип узла в последовательности может понадобиться в том случае, если выражение возвращает последовательность узлов. В следующем примере показано использование синтаксиса типа последовательности для определения типа узла, возвращаемого выражением. Можно использовать следующие типы последовательности:

  • item() — соответствует любому элементу последовательности.
  • node() — определяет, является ли последовательность узлом.
  • processing-instruction() — определяет, возвращает ли выражение инструкцию по обработке.
  • comment() — определяет, возвращает ли выражение комментарий.
  • document-node() — определяет, возвращает ли выражение узел документа.

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

Пример A

В этом примере выполняется несколько запросов к нетипизированной xml-переменной. В этих запросах демонстрируется использование указанных типов последовательности.

DECLARE @var XML
SET @var = '<?xml-stylesheet href="someValue" type="text/xsl" ?>
<root>text node
  <!-- comment 1 --> 
  <a>Data a</a>
  <!-- comment  2 -->
</root>'

В первом запросе выражение возвращает типизированное значение элемента <a>. Во втором запросе выражение возвращает элемент <a>. Оба результата являются элементами. Поэтому оба запроса возвращают значение True.

SELECT @var.query('data(/root[1]/a[1]) instance of item()')
SELECT @var.query('/root[1]/a[1] instance of item()')

Все выражения языка XQuery, содержащиеся в трех следующих запросах, возвращают дочерний узел элемента <root>. Поэтому выражение типа последовательности instance of node() возвращает значение True, а два других выражения (instance of text() и instance of document-node()) — значение False.

SELECT @var.query('(/root/*)[1] instance of node()')
SELECT @var.query('(/root/*)[1] instance of text()')
SELECT @var.query('(/root/*)[1] instance of document-node()') 

В следующем примере выражение instance of document-node() возвращает значение True, так как родителем элемента <root> является узел документа.

SELECT @var.query('(/root/..)[1] instance of document-node()') -- true

В следующем запросе выражение извлекает первый узел XML-экземпляра. Так как он является узлом инструкции по обработке, выражение instance of processing-instruction() возвращает значение True.

SELECT @var.query('(/node())[1] instance of processing-instruction()')

Ограничения реализации

Особые ограничения:

  • Синтаксис document-node() с типом содержимого не поддерживается.
  • Синтаксис processing-instruction(name) не поддерживается.

Проверка элемента

Проверка элемента используется для сопоставления узла элемента, возвращаемого выражением, с узлом элемента с указанным именем и типом. Можно использовать следующие проверки элемента:

element ()
element(ElementName)
element(ElementName, ElementType?) 
element(*, ElementType?)

Проверка атрибута

В ходе проверки атрибута выясняется, является ли атрибут, возвращенный выражением, узлом. Можно использовать следующие проверки атрибутов.

attribute()

attribute(AttributeName)

attribute(AttributeName, AttributeType)

Примеры проверки

В представленных ниже примерах приведены ситуации, в которых можно использовать проверки элемента и атрибута.

Пример A

Представленная XML-схема определяет сложный тип данных CustomerType, в котором элементы <firstName> и <lastName> являются необязательными. В указанном XML-экземпляре может понадобиться определить, существует ли запись, содержащая фамилию определенного покупателя.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="myNS" xmlns:ns="myNS">
  <complexType name="CustomerType">
     <sequence>
        <element name="firstName" type="string" minOccurs="0" 
                  nillable="true" />
        <element name="lastName" type="string" minOccurs="0"/>
     </sequence>
  </complexType>
  <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO
DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS">
<firstName>SomeFirstName</firstName>
<lastName>SomeLastName</lastName>
</x:customer>'

В представленном ниже запросе выражение instance of element (firstName) используется для определения, является ли элемент <firstName> первым дочерним элементом узла <customer>. Если является, выражение возвращает значение True.

SELECT @var.query('declare namespace x="myNS"; 
     (/x:customer/*)[1] instance of element (firstName)')
GO

Если удалить элемент <firstName> из экземпляра, выражение возвращает значение False.

Также можно использовать следующее:

  • Синтаксис типа последовательности element(ElementName, ElementType?), представленный в следующем запросе. Указанный запрос относится к узлу элемента с именем firstName и типом xs:string.

    SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer/*)[1] instance of element (firstName, xs:string?)')
    
  • Синтаксис типа последовательности element(*, type?), представленный в следующем запросе. Указанный запрос извлекает узел элементов, имеющий тип xs:string, независимо от его имени.

    SELECT @var.query('declare namespace x="myNS"; (/x:customer/*)[1] instance of element (*, xs:string?)')
    GO
    

Пример Б

В следующем примере показано, как определить, является ли узел, возвращенный выражением, элементом узла с указанным именем. В нем используется проверка element().

В следующем примере два элемента <Customer> XML-экземпляра, к которому происходит запрос, имеют два разных типа данных: CustomerType и SpecialCustomerType. Предположим, что необходимо выяснить тип элемента <Customer>, возвращенного выражением. Следующая коллекция XML-схем определяет типы данных CustomerType и SpecialCustomerType.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
          targetNamespace="myNS"  xmlns:ns="myNS">
  <complexType name="CustomerType">
    <sequence>
      <element name="firstName" type="string"/>
      <element name="lastName" type="string"/>
    </sequence>
  </complexType>
  <complexType name="SpecialCustomerType">
     <complexContent>
       <extension base="ns:CustomerType">
        <sequence>
            <element name="Age" type="int"/>
        </sequence>
       </extension>
     </complexContent>
    </complexType>
   <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

Указанная коллекция XML-схем используется для создания типизированной xml-переменной. XML-экземпляр, связанный с данной переменной, содержит два элемента <customer> разных типов. Первый элемент имеет тип данных CustomerType, а второй элемент — SpecialCustomerType.

DECLARE @var XML(SC)
SET @var = '
<x:customer xmlns:x="myNS">
   <firstName>FirstName1</firstName>
   <lastName>LastName1</lastName>
</x:customer>
<x:customer xsi:type="x:SpecialCustomerType" xmlns:x="myNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <firstName> FirstName2</firstName>
   <lastName> LastName2</lastName>
   <Age>21</Age>
</x:customer>'

В следующем запросе выражение instance of element (*, x:SpecialCustomerType ?) возвращает значение False, так как оно возвращает первый элемент результата, не имеющий тип данных SpecialCustomerType.

SELECT @var.query('declare namespace x="myNS"; 
    (/x:customer)[1] instance of element (*, x:SpecialCustomerType ?)')

Если изменить выражение, используемое в предыдущем запросе, и извлечь второй элемент <customer> (/x:customer)[2]), то результатом выполнения выражения instance of будет значение True.

Пример В

В данном примере используется проверка атрибута. Следующая XML-схема определяет сложный тип CustomerType с атрибутами CustomerID и Age. Атрибут Age является необязательным. Для указанного XML-экземпляра может понадобиться определить, имеется ли у элемента <customer> атрибут Age.

CREATE XML SCHEMA COLLECTION SC AS N'
<schema xmlns="http://www.w3.org/2001/XMLSchema"
       targetNamespace="myNS" xmlns:ns="myNS">
<complexType name="CustomerType">
  <sequence>
     <element name="firstName" type="string" minOccurs="0" 
               nillable="true" />
     <element name="lastName" type="string" minOccurs="0"/>
  </sequence>
  <attribute name="CustomerID" type="integer" use="required" />
  <attribute name="Age" type="integer" use="optional" />
 </complexType>
 <element name="customer" type="ns:CustomerType"/>
</schema>
'
GO

Результатом следующего запроса является значение True, так как имеется узел атрибута с именем Age в экземпляре XML, к которому производится запрос. В данном выражении используется проверка атрибута attribute(Age). Так как атрибуты не упорядочены, то в запросе вначале извлекаются все атрибуты с помощью выражения FLWOR, а затем производится их проверка с помощью выражения instance of. В данном примере вначале создается коллекция XML-схем для определения xml-переменных.

DECLARE @var XML(SC)
SET @var = '<x:customer xmlns:x="myNS" CustomerID="1" Age="22" >
<firstName>SomeFName</firstName>
<lastName>SomeLName</lastName>
</x:customer>'
SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age)) THEN
        "true"
        ELSE
        ()')   
GO

Если из экземпляра удалить необязательный атрибут Age, предыдущий запрос возвращает значение False.

Для проверки атрибута необходимо указать его имя и ввести (attribute(name,type)).

SELECT @var.query('declare namespace x="myNS"; 
FOR $i in /x:customer/@*
RETURN
    IF ($i instance of attribute (Age, xs:integer)) THEN
        "true"
        ELSE
        ()')

Также можно указать синтаксис типа последовательности attribute(*, type). Если тип атрибута соответствует указанному типу вне зависимости от его имени, узел атрибута считается удовлетворяющим запросу.

Ограничения реализации

Особые ограничения:

  • При проверке элементов имя типа должно следовать за признаком вхождения (?).
  • элемент(ElementName, TypeName) не поддерживается.
  • элемент(*, TypeName) не поддерживается.
  • Синтаксис элемент_схемы() не поддерживается.
  • атрибут_схемы(AttributeName) не поддерживается.
  • Явные запросы для xsi:type или xsi:nil не поддерживаются.

См. также

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

Выражения SequenceType (XQuery)
Основы языка XQuery

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

Работа с приложением SQL Server Profiler

Справка и поддержка

Получение помощи по SQL Server 2005