Правила приведения типов в запросах XQuery
В следующей схеме спецификаций функций и операторов языков W3C XQuery 1.0 и XPath 2.0 показаны встроенные типы данных. К ним относятся встроенные примитивные и встроенные производные типы.
В этом разделе описаны правила приведения типов, применяемые при приведении одного типа к другому с помощью одного из следующих методов.
Явное приведение с помощью оператора cast as или функций-конструкторов типов (например, xs:integer("5")).
Неявное приведение, выполняемое в процессе повышения типов.
Явное приведение
В следующей таблице показано разрешенное приведение встроенных типов-примитивов друг к другу.
Встроенный тип-примитив может быть приведен к другому встроенному типу-примитиву на основе правил, указанных в таблице.
Тип-примитив может быть приведен к любому производному от него типу. Например, можно привести тип xs:decimal к типу xs:integer, а тип xs:decimal — к типу xs:long.
Производный тип может быть приведен к любому типу, являющемуся его предком в иерархии типов, вплоть до его встроенного примитивного базового типа. Например, можно привести тип xs:token к типу xs:normalizedString или xs:string.
Производный тип может быть приведен к типу-примитиву в случае, если его примитивный тип-предок может быть приведен к целевому типу. Например, можно привести производный тип xs:integer к типу-примитиву xs:string, так как примитивный тип-предок типа xs:integer — тип xs:decimal — может быть приведен к типу xs:string.
Производный тип может быть приведен к другому производному типу, если примитивный тип-предок исходного типа может быть приведен к примитивному типу-предку целевого типа. Например, можно привести тип xs:integer к типу xs:token, так как тип xs:decimal можно привести к типу xs:string.
Правила приведения определяемых пользователем типов к встроенным являются теми же, что и для встроенных типов. Например, можно определить тип myInteger как производный от типа xs:integer. Затем тип myInteger можно будет привести к типу xs:token, так как тип xs:decimal можно привести к типу xs:string.
Следующие способы приведения типов не поддерживаются.
Приведение к списковым типам или списковых типов к другим недопустимо. К таким типам относятся как пользовательские, так и встроенные списковые типы например xs:IDREFS, xs:ENTITIES или xs:NMTOKENS.
Приведение типа xs:QName к другим типам или других типов к нему не поддерживается.
Типы xs:NOTATION и полностью упорядоченные подтипы временной длительности xdt:yearMonthDuration и xdt:dayTimeDuration не поддерживаются. В результате приведение к этим типам или этих типов к другим не поддерживается.
В следующих примерах показано явное приведение типов.
Пример A
В следующем примере запрашивается переменная XML-типа. Запрос возвращает последовательность значения простого типа, типизированного как xs:string.
declare @x xml
set @x = '<e>1</e><e>2</e>'
select @x.query('/e[1] cast as xs:string?')
go
Пример Б
В следующем примере запрашивается типизированная переменная xml. Сначала создается коллекция XML-схем. Затем эта коллекция используется для создания типизированной переменной xml. В схеме содержатся сведения о типизации для экземпляра XML, назначенного переменной. После этого запросы направляются к данной переменной.
create xml schema collection myCollection as N'
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="A" type="xs:string"/>
<xs:element name="B" type="xs:string"/>
<xs:element name="C" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>'
go
Следующий запрос возвращает статическую ошибку, так как неизвестно, сколько элементов верхнего уровня <root> присутствует в экземпляре документа.
declare @x xml(myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>
<root><A>4</A><B>5</B><C>6</baz></C>'
select @x.query('/root/A cast as xs:string?')
go
При указании в выражении одиночного элемента <root> запрос завершается успешно. Запрос возвращает последовательность значения простого типа, типизированного как xs:string.
declare @x xml(myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>
<root><A>4</A><B>5</B><C>6</C></root>'
select @x.query('/root[1]/A cast as xs:string?')
go
В следующем примере переменная XML-типа содержит ключевое слово document, указывающее на коллекцию XML-схем. Это слово указывает, что экземпляр XML должен представлять собой документ с одиночным элементом верхнего уровня. Если в экземпляре XML будет создано два элемента <root>, будет возвращена ошибка.
declare @x xml(document myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>
<root><A>4</A><B>5</B><C>6</C></root>'
go
Можно изменить экземпляр таким образом, чтобы он содержал только один элемент верхнего уровня, и запрос будет работать. Запрос вновь возвращает последовательность значения простого типа, типизированного как xs:string.
declare @x xml(document myCollection)
set @x = '<root><A>1</A><B>2</B><C>3</C></root>'
select @x.query('/root/A cast as xs:string?')
go
Неявное приведение
Неявное приведение разрешено только для числовых типов и нетипизированных атомарных типов. Например, следующая функция min() возвращает минимальное из двух значений:
min(xs:integer("1"), xs:double("1.1"))
В данном примере два значения, переданные функции min() языка XQuery, принадлежат к разным типам. Поэтому неявное приведение выполняется в момент, когда тип integer повышается до типа double, а затем два значения типа double сравниваются между собой.
Повышение типов, описанное в данном примере, выполняется по следующим правилам.
Встроенный производный числовой тип можно повышать до его базового типа. Например, тип integer можно повысить до типа decimal.
Тип decimal можно повысить до типа float, а тип float можно повысить до типа double.
Так как неявное приведение допустимо только для числовых типов, следующие операции недопустимы.
Неявное приведение строковых типов недопустимо. Например, если вместо двух ожидаемых значений типа string будет передано одно значение типа string и одно — типа token, неявное приведение выполняться не будет, и будет возвращена ошибка.
Неявное приведение числовых типов к строковым недопустимо. Например, в случае передачи значения целого типа функции, принимающей параметр строкового типа, неявное приведение выполняться не будет, и будет возвращена ошибка.
Приведение значений
При приведении одного типа к другому фактические значения трансформируются из пространства значений исходного типа в пространство значений целевого типа. Например, при приведении значения типа xs:decimal к типу xs:double значение decimal будет преобразовано в значение double.
Ниже приведены некоторые правила преобразования.
Приведение значения типа string или untypedAtomic к другому типу
Значение, которое приводится к типу string или untypedAtomic, преобразуется таким же образом, что и при проверке значения на основе правил целевого типа. Сюда входят правила сопоставления с ожидаемым шаблоном и обработки пробелов. Например, следующая операция завершится успехом, а результатом ее будет значение типа double 1.1e0:
xs:double("1.1")
При приведении типов string или untypedAtomic к двоичным типам, например xs:base64Binary или xs:hexBinary, входные значения должны быть зашифрованы в формате base64 или представлены в шестнадцатиричной кодировке соответственно.
Приведение значения к типу string или untypedAtomic
При приведении значения к типу string или untypedAtomic оно будет преобразовано в свое каноническое лексическое представление в языке XQuery. Конкретно это означает, что значение, которое при вводе укладывалось в заданный шаблон или другое ограничение, не будет представлено в соответствии с данным ограничением. Для информирования об этом пользователей в SQL Server типы снабжаются флагами, и если ограничение типа может вызвать проблему, то при загрузке таких типов в коллекцию схем выдается предупреждение.
При приведении значения типа xs:float к типу xs:double или какому-либо из его подтипов, к типу string или untypedAtomic, значение будет представлено в экспоненциальной записи. Это производится только в случае, если абсолютное значение данного значения меньше 1.0E-6 или же больше или равно 1.0E6. Таким образом, 0 сериализуется в экспоненциальном представлении в форме 0.0E0.
Например, операция xs:string(1.11e1) возвращает строковое значение "11.1", в то время как операция xs:string(-0.00000000002e0) возвращает строковое значение "-2.0E-11".
При приведении двоичных типов, например xs:base64Binary или xs:hexBinary, к типу string или untypedAtomic, двоичные значения будут зашифрованы в формате base64 или представлены в шестнадцатиричной кодировке соответственно.
Приведение значения к числовому типу
При приведении значения одного числового типа к значению другого числового типа оно сопоставляется из одного пространства значений с другим без строковой сериализации. Если значение не удовлетворяет ограничениям целевого типа, применяются следующие правила.
Если исходное значение уже является числовым, а целевой тип — xs:float либо его подтип, для которого допустимы значения -INF и INF, и приведение исходного числового значения к целевому типу вызовет переполнение, значение сопоставляется с INF, если оно положительное, и с -INF — если отрицательное. Если для целевого типа недопустимы значения INF и -INF и может произойти переполнение, приведение завершается неудачей и SQL Server выдает в качестве результата пустую последовательность.
Если исходное значение уже является числовым, а целевой тип — числовой и его диапазон приемлемых значений включает 0, -0e0 или 0e0 и приведение исходного числового значения к целевому типу вызовет потерю точности, сопоставление значения выполняется следующим образом.
Для десятичного целевого типа значению сопоставляется 0.
В случае потери точности отрицательного значения ему сопоставляется -0e0.
В случае потери точности положительного значения для целевого типа с плавающей точкой или с двойной точностью ему сопоставляется 0e0.
Если в пространство значений целевого типа не входит ноль, приведение завершается неудачей, а результатом является пустая последовательность.
Обратите внимание, что при приведении значения к двоичному типу с плавающей запятой, например xs:float, xs:double или любому из их подтипов, точность может снизиться.
Ограничения реализации
Существуют следующие ограничения.
Значение NaN (нечисловое) с плавающей запятой не поддерживается.
На значения, доступные для приведения, накладываются ограничения реализации целевых типов. Например, нельзя привести строку даты, содержащую отрицательный год, к типу xs:date. Если значение предоставляется во время выполнения, результатом такого приведения будет пустая последовательность (а не ошибка времени выполнения).