Выражения SequenceType (XQuery)

В XQuery значение всегда является последовательностью. Тип значения называется типом последовательности. Тип последовательности можно использовать в выражениях XQuery с оператором instance of. Для обращения к типам в выражениях XQuery применяется синтаксис SequenceType, описанный в спецификации XQuery.

Кроме того, в выражениях XQuery с оператором cast as можно использовать имена атомарных типов. В SQL Server операции instance of и cast as языка XQuery над типами последовательности поддерживаются частично.

Оператор instance of

Оператор instance of можно использовать для определения динамического типа (или типа периода выполнения) значения указанного выражения. Например:

Expression instance of SequenceType[Occurrence indicator]

Обратите внимание, что в операторе instance of аргумент Occurrence indicator количество элементов в итоговой последовательности. Если он не указан, предполагается, что количество элементов равно 1. В SQL Server в качестве этого аргумента используется только вопросительный знак (?) . Признак встречаемости ? свидетельствует о том, что выражение может возвратить один элемент или не возвратить ни одного. При указанном признаке встречаемости ? оператор instance of возвращает True, если тип выражения соответствует указанному типу SequenceType, независимо от того, возвращает ли выражение единственный элемент или пустую последовательность.

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

Примечание Признаки встречаемости + (плюс) и * (звездочка) в SQL Server не поддерживаются.

Применение оператораinstance of языка XQuery поясняют следующие примеры.

Пример А

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

Следующий запрос возвращает True, потому что значение 125 является экземпляром указанного типа xs:integer:

declare @x xml
set @x=''
select @x.query('125 instance of xs:integer')
go

Следующий запрос возвращает True, потому что значение, возвращаемое выражением /a[1], то есть первым операндом, является элементом.

declare @x xml
set @x='<a>1</a>'
select @x.query('/a[1] instance of element()')
go

Подобно этому, в следующем запросе оператор instance of также возвращает True, потому что тип значения первого выражения является атрибутом:

declare @x xml
set @x='<a attr1="x">1</a>'
select @x.query('/a[1]/@attr1 instance of attribute()')
go

В следующем примере выражение data(/a[1] возвращает атомарное значение, типизированное как xdt:untypedAtomic. Поэтому оператор instance of возвращает True.

declare @x xml
set @x='<a>1</a>'
select @x.query('data(/a[1]) instance of xdt:untypedAtomic')
go

В следующем запросе выражение data(/a[1]/@attrA возвращает нетипизированное атомное значение. Поэтому оператор instance of возвращает True.

declare @x xml
set @x='<a attrA="X">1</a>'
select @x.query('data(/a[1]/@attrA) instance of xdt:untypedAtomic')
go

Пример Б

В этом примере запрашиваются данные типизированного XML-столбца образца базы данных AdventureWorks. Сведения о типах предоставляет связанная с этим столбцом коллекция XML-схем.

В этом выражении метод data() возвращает типизированное значение атрибута ProductModelID, который в соответствии с ассоциированной со столбцом схемой имеет тип xs:string. Поэтому оператор instance of возвращает значение True.

SELECT CatalogDescription.query('
   declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
   data(/PD:ProductDescription[1]/@ProductModelID) instance of xs:string
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19

Дополнительные сведения см. в разделе Сравнение типизированного и нетипизированного XML.

В следующих запросахлогическое выражение instance of используется для определения того, имеет ли атрибут LocationID тип xs:integer.

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

Следующий запрос выполняется для типизированного XML-столбца CatalogDescription. Сведения о типах предоставляет связанная с этим столбцом коллекция XML-схем.

Для проверки того, возвращает ли выражение /PD:ProductDescription[1] узел с конкретным именем и типом, в операторе instance of используется выражение element(ElementName, ElementType?).

SELECT CatalogDescription.query('
     declare namespace PD="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     /PD:ProductDescription[1] instance of element(PD:ProductDescription, PD:ProductDescription?)
    ') as Result
FROM  Production.ProductModel
where ProductModelID=19

Запрос возвращает значение True.

Пример В

При использовании объединенных типов на оператор instance of в SQL Server распространяется ограничение: если тип элемента или атрибута является объединенным типом, оператор instance of не всегда может определить точный тип. Таким образом, если атомарные типы, использованные в выражении SequenceType, не являются самым старшим родительским элементом фактического типа выражения в иерархии simpleType, запрос возвращает False. Иначе говоря, атомарные типы, указанные в выражении SequenceType, должны быть непосредственным дочерним элементом anySimpleType. Дополнительные сведения об иерархии типов см. в разделе Правила приведения типов в запросах XQuery.

В приведенном ниже запросе выполняется следующее:

  • Создается коллекция XML-схем с определенным в ней объединенным типом, таким как целочисленный или строковый тип.

  • С использованием коллекции XML-схем объявляется типизированная переменная xml.

  • Этой переменной назначается экземпляр XML.

  • Выполняется запрос переменной, чтобы продемонстрировать работу оператора instance of с объединенным типом.

Запрос:

CREATE XML SCHEMA COLLECTION MyTestSchema AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ns" xmlns:ns="http://ns">
<simpleType name="MyUnionType">
<union memberTypes="integer string"/>
</simpleType>
<element name="TestElement" type="ns:MyUnionType"/>
</schema>'
Go

Следующий запрос возвращает False, потому что тип SequenceType, указанный в выражении instance of, не является самым старшим родительским типом фактического типа указанного выражения. Иначе говоря, значение <TestElement> имеет целочисленный тип, а его самый старший родительский тип — xs:decimal. Однако он не указан в качестве второго операнда оператора instance of.

SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)

SET @var = '<TestElement xmlns="http://ns">123</TestElement>'

SELECT @var.query('declare namespace ns="http://ns" 
   data(/ns:TestElement[1]) instance of xs:integer')
go

Так как самым старшим родительским типом по отношению к xs:integer является тип xs:decimal, то, если в этом запросе указать в качестве SequenceType тип xs:decimal, запрос возвратит True.

SET QUOTED_IDENTIFIER ON
DECLARE @var XML(MyTestSchema)
SET @var = '<TestElement xmlns="http://ns">123</TestElement>'
SELECT @var.query('declare namespace ns="http://ns"   
   data(/ns:TestElement[1]) instance of xs:decimal')
go

Пример Г

В этом примере сначала создается коллекция XML-схем, на основе которой осуществляется типизация переменной xml. После этого для пояснения функциональности оператора instance of выполняется запрос типизированной переменной xml.

Следующая коллекция XML-схем определяет простой тип myType и элемент <root> типа myType:

drop xml schema collection SC
go
CREATE XML SCHEMA COLLECTION SC AS '
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="myNS" xmlns:ns="myNS"
xmlns:s="https://schemas.microsoft.com/sqlserver/2004/sqltypes">
      <import namespace="https://schemas.microsoft.com/sqlserver/2004/sqltypes"/>
      <simpleType name="myType">
           <restriction base="s:varchar">
                  <maxLength value="20"/>
            </restriction>
      </simpleType>
      <element name="root" type="ns:myType"/>
</schema>'
Go

В следующем коде создается типизированная переменная xml и выполняется запрос этой переменной:

DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS"; 
   data(/ns:root[1]) instance of ns:myType')
go

Так как тип myType наследуется по ограничению от типа varchar, который определен в схеме sqltypes, в этом случае оператор instance of также возвратит True.

DECLARE @var XML(SC)
SET @var = '<root xmlns="myNS">My data</root>'
SELECT @var.query('declare namespace sqltypes = "https://schemas.microsoft.com/sqlserver/2004/sqltypes";
declare namespace ns="myNS"; 
data(/ns:root[1]) instance of sqltypes:varchar?')
go

Пример Д

В следующем примере выражение получает одно из значений атрибута IDREFS, после чего с помощью оператора instance of определяется, имеет ли это значение тип IDREF. В примере выполняются следующие действия:

  • Создается коллекция XML-схем, в которой элемент <Customer> имеет атрибут OrderList типа IDREFS, а элемент <Order> — атрибут OrderID типа ID.

  • Создается типизированная переменная xml, которой назначается экземпляр XML.

  • Задается запрос, который должен быть выполнен для переменной. Выражение запроса получает идентификатор первого заказа из атрибута OrderList (типа IDREFS) первого элемента <Customer>. Это значение имеет тип IDREF. Таким образом, оператор instance of возвращает True.

create xml schema collection SC as
'<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:Customers="Customers" targetNamespace="Customers">
            <element name="Customers" type="Customers:CustomersType"/>
            <complexType name="CustomersType">
                        <sequence>
                            <element name="Customer" type="Customers:CustomerType" minOccurs="0" maxOccurs="unbounded" />
                        </sequence>
            </complexType>
             <complexType name="OrderType">
                <sequence minOccurs="0" maxOccurs="unbounded">
                            <choice>
                                <element name="OrderValue" type="integer" minOccurs="0" maxOccurs="unbounded"/>
                            </choice>
                </sequence>                                           
                <attribute name="OrderID" type="ID" />
            </complexType>

            <complexType name="CustomerType">
                <sequence minOccurs="0" maxOccurs="unbounded">
                            <choice>
                                <element name="spouse" type="string" minOccurs="0" maxOccurs="unbounded"/>
                                <element name="Order" type="Customers:OrderType" minOccurs="0" maxOccurs="unbounded"/>
                            </choice>
                </sequence>                                           
                <attribute name="CustomerID" type="string" />
                <attribute name="OrderList" type="IDREFS" />
            </complexType>
 </schema>'
go
declare @x xml(SC)
set @x='<CustOrders:Customers xmlns:CustOrders="Customers">
                <Customer CustomerID="C1" OrderList="OrderA OrderB"  >
                              <spouse>Jenny</spouse>
                                <Order OrderID="OrderA"><OrderValue>11</OrderValue></Order>
                                <Order OrderID="OrderB"><OrderValue>22</OrderValue></Order>

                </Customer>
                <Customer CustomerID="C2" OrderList="OrderC OrderD" >
                                <spouse>John</spouse>
                                <Order OrderID="OrderC"><OrderValue>33</OrderValue></Order>
                                <Order OrderID="OrderD"><OrderValue>44</OrderValue></Order>

                        </Customer>
                <Customer CustomerID="C3"  OrderList="OrderE OrderF" >
                                <spouse>Jane</spouse>
                                <Order OrderID="OrderE"><OrderValue>55</OrderValue></Order>
                                <Order OrderID="OrderF"><OrderValue>55</OrderValue></Order>
                </Customer>
                <Customer CustomerID="C4"  OrderList="OrderG"  >
                                <spouse>Tim</spouse>
                                <Order OrderID="OrderG"><OrderValue>66</OrderValue></Order>
                        </Customer>
                <Customer CustomerID="C5"  >
                </Customer>
                <Customer CustomerID="C6" >
                </Customer>
                <Customer CustomerID="C7"  >
                </Customer>
</CustOrders:Customers>'

select @x.query(' declare namespace CustOrders="Customers"; 
 data(CustOrders:Customers/Customer[1]/@OrderList)[1] instance of xs:IDREF ? ') as XML_result

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

Существуют следующие ограничения.

  • Оператор instance of не поддерживает сравнение типов последовательностей schema-element() и schema-attribute().

  • Полные последовательности, например (1,2) instance of xs:integer*, не поддерживаются.

  • При использовании формы типа последовательности element() с заданным именем типа, такой как element(ElementName, TypeName), тип должен быть дополнен вопросительным знаком (?). Например, инструкция element(Title, xs:string?) указывает, что элемент может иметь значение NULL. SQL Server не поддерживает идентификацию свойства xsi:nil во время выполнения с помощью инструкции instance of.

  • Если значение выражения извлекается из элемента или атрибута, типизированного как объединенный тип, SQL Server может идентифицировать только примитивный непроизводный тип, от которого произведен тип значения. Например, если элемент <e1> определен как статический тип (xs:integer | xs:string), следующее выражение возвратит False.

    data(<e1>123</e1>) instance of xs:integer
    

    Однако выражение data(<e1>123</e1>) instance of xs:decimal возвратит True.

  • В случае типов последовательностей processing-instruction() и document-node() поддерживаются только формы без аргументов. Например, форма processing-instruction() поддерживается, но форма processing-instruction('abc') недопустима.

Оператор cast as

Оператор cast as можно использовать для преобразования значения в специфический тип данных. Например:

Expression cast as  AtomicType?

SQL Server требует, чтобы после операнда AtomicType был указан вопросительный знак (?). Например, в следующем запросе выражение "2" cast as xs:integer? преобразует строковое значение в целое число:

declare @x xml
set @x=''
select @x.query('"2" cast as xs:integer?')

В следующем запросе метод data() возвращает типизированное значение атрибута ProductModelID, то есть строковый тип: Оператор cast as преобразует это значение в тип xs:integer.

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' AS PD)
SELECT CatalogDescription.query('
   data(/PD:ProductDescription[1]/@ProductModelID) cast as xs:integer?
') as Result
FROM Production.ProductModel
WHERE ProductModelID = 19

Явно использовать метод data() в этом запросе не требуется. Оператор cast as неявно выполняет атомизацию входного выражения.

Функции-конструкторы

Можно использовать функции-конструкторы атомарных типов. Например, вместо выражения "2" cast as xs:integer? с оператором cast as можно использовать функцию-конструктор xs:integer():

declare @x xml
set @x=''
select @x.query('xs:integer("2")')

Следующий код возвращает значение xs:date, равное 2000-01-01Z:

declare @x xml
set @x=''
select @x.query('xs:date("2000-01-01Z")')

Конструкторы можно применять и при работе с пользовательскими атомарными типами. Например, если связанная с типом данных XML коллекция XML-схем определяет простой тип, для возврата значения этого типа можно использовать конструктор myType() .

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

  • Выражения typeswitch, castable и treat языка XQuery не поддерживаются.

  • Оператор cast as требует, чтобы после атомарного типа был указан вопросительный знак (?).

  • При приведении типа тип xs:QName не поддерживается. Используйте вместо этого функцию expanded-QName.

  • Типы xs:date, xs:time и xs:datetime требуют, чтобы был указан часовой пояс, для чего применяется буква Z.

    Например, следующий запрос завершается неудачей, потому что часовой пояс не указан:

    DECLARE @var XML
    SET @var = ''
    SELECT @var.query(' <a>{xs:date("2002-05-25")}</a>')
    go
    

    Если дополнить значение признаком часового пояса Z, запрос выполняется успешно:

    DECLARE @var XML
    SET @var = ''
    SELECT @var.query(' <a>{xs:date("2002-05-25Z")}</a>')
    go
    

    Результат:

    <a>2002-05-25Z</a>
    

См. также

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

Выражения языка XQuery

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