Типы данных XPath (SQLXML 4.0)
Набор типов в Microsoft SQL Server, XPath и XML Schema (XSD) сильно отличается. Например, в XPath отсутствуют целочисленные типы данных и тип данных для обозначения даты, а в SQL Server и XSD таких типов множество. Типы данных XSD определяют время с точностью до наносекунды, а SQL Server только до одной трехсотой доли секунды. Поэтому не всегда возможно сопоставить один тип другому. Дополнительные сведения о сопоставлении типов данных SQL Server и XSD см. в разделе Приведение типов данных и заметка sql:datatype (SQLXML 4.0).
В XPath есть три типа данных: string, number и boolean. Тип данных number — это всегда тип двойной точности с плавающей запятой по стандарту IEEE 754. Тип данных SQL Server float(53) ближе всего к типу number в XPath. Однако float(53) не совсем соответствует IEEE 754. В частности, этот тип не содержит ни значений NaN (Not-a-Number), ни значений бесконечности. Попытка преобразовать нечисловую строку в тип number и попытка деления на ноль вызывают ошибки.
Преобразования в XPath
При использовании запроса XPath — например, OrderDetail[@UnitPrice > "10.0"], — явные и неявные преобразования типов данных могут различными неочевидными способами изменить значение запроса. Поэтому важно знать, как реализована система типов данных в XPath. Спецификация языка XPath — рекомендации консорциума W3C XML Path Language (XPath) версии 1.0 от 8 October 1999; с этим документом можно ознакомиться на веб-узле W3C по адресу http://www.w3.org/TR/1999/PR-xpath-19991008.html.
Операторы XPath делятся на четыре категории:
Логические операторы (и, или)
Операторы отношений (<, >, <=, >=)
Операторы равенства (=, !=)
Арифметические операторы (+, -, *, div, mod);
Операторы разных категорий по-разному преобразуют операнды. При необходимости операторы XPath неявно преобразуют операнды. Арифметические операторы преобразуют операнды к типу number, и результатом их выполнения является число. Логические операторы преобразуют операнды к типу boolean, и результатом их выполнения является логическое значение. Результатом выполнения операторов отношения и операторов равенства является логическое значение. Однако правила преобразования, которыми пользуются операторы, зависят от первоначальных типов операндов, как показано в таблице.
Операнд |
Реляционный оператор |
Оператор равенства |
---|---|---|
Оба операнда представляют собой наборы узлов. |
Значение TRUE, если и только в том случае, когда в первом наборе узлов есть такой узел и во втором наборе узлов есть такой узел, что сравнение их значений string вернет значение TRUE. |
То же. |
Один — набор узлов, другой — string. |
Значение TRUE, если и только если в наборе узлов есть такой узел, который после преобразования в number при сравнении с объектом типа string, преобразованным в тип number вернет значение TRUE. |
Значение TRUE, если и только в том случае, когда в наборе узлов есть такой узел, который после преобразования в string при сравнении с string вернет значение TRUE. |
Один — набор узлов, другой — number. |
Значение TRUE, если и только в том случае, когда в наборе узлов есть такой узел, который после преобразования в number при сравнении с number вернет значение TRUE. |
То же. |
Один — набор узлов, другой — boolean. |
Значение TRUE, если и только если в наборе узлов есть такой узел, который после преобразования в boolean, а затем в number при сравнении с объектом типа boolean, преобразованным в тип number, вернет значение TRUE. |
Значение TRUE, если и только в том случае, когда в наборе узлов есть такой узел, который после преобразования в boolean при сравнении с boolean вернет значение TRUE. |
Ни один из них не представляет собой набор узлов. |
Преобразует оба операнда к типу number, а затем сравнивает их. |
Преобразует оба операнда к одному типу , а затем сравнивает их. Преобразует к типу boolean, если хотя бы один из операндов принадлежит к типу boolean, и к типу number, если хотя бы один из операндов принадлежит к типу number; в противном случае преобразует к типу string. |
![]() |
---|
Поскольку операторы отношений XPath всегда преобразуют операнды к типу number, сравнение типов string невозможно. Чтобы включить сравнение дат, SQL Server 2000 предлагает следующее изменение спецификации XPath: Когда оператор отношения сравнивает тип string с типом string, набор узлов с типом string или набор узлов со строковыми значениями с другим таким же набором, проводится сравнение по типу string, а не по типу number. |
Преобразования наборов узлов
Преобразования наборов узлов не всегда интуитивно понятны. Чтобы преобразовать набор узлов в тип string, берется строковое значение только первого узла набора. Чтобы преобразовать набор узлов к типу number, он сначала преобразуется в тип string, а затем значение типа string преобразуется в тип number. Чтобы преобразовать набор узлов к типу boolean, производится его проверка на существование.
![]() |
---|
SQL Server не проводит выборки из наборов узлов по положению в наборе. Например, запрос XPath Customer[3] означает третьего заказчика; в SQL Server такой тип выборки не поддерживается. Поэтому преобразования набора узлов в тип string или в тип number согласно спецификации XPath не реализованы. SQL Server использует семантику «любой» там, где спецификация XPath использует семантику «первый». Например, согласно спецификации W3C по XPath, запрос XPath Order[OrderDetail/@UnitPrice > 10.0] выберет заказы, у которых в первой строке OrderDetail значится цена UnitPrice, превышающая 10.0. В SQL Server этот запрос XPath выберет заказы, у которых в любой строке OrderDetail значится цена UnitPrice, превышающая 10.0. |
Преобразование к типу boolean проводит проверку на существование; поэтому запрос XPath Products[@Discontinued=true()] эквивалентен выражению SQL "Products.Discontinued is not null", а не выражению SQL "Products.Discontinued = 1". Чтобы запрос был эквивалентен последнему из приведенных выражений SQL, набор узлов сначала надо преобразовать в тип, отличный от boolean — например, number. Например, Products[number(@Discontinued) = true()].
Большинство операторов реализовано так, что они возвращают TRUE, если их результат равен TRUE хотя бы для одного (любого) узла набора; поэтому они возвращают FALSE, если набор узлов пуст. Таким образом, если набор узлов A пуст, оба оператора A = B и A != B вернут FALSE, а not(A=B) и not(A!=B) — TRUE.
Обычно атрибут или элемент, сопоставленный столбцу, существует, если значение этого столбца в базе данных не равно null. Элементы, сопоставляемые строкам, существуют, если существует хотя бы один из их дочерних элементов. Дополнительные сведения см. в разделах Использование заметки sql:relation (схема XDR) и Использование заметки sql:field (схема XDR).
![]() |
---|
Элементы с аннотацией is-constant существуют всегда. Следовательно, предикаты XPath нельзя использовать для элементов, помеченных как is-constant. Дополнительные сведения см. в разделе Создание постоянных элементов с помощью sql:is-constant (схема XDR). |
При преобразовании набора узлов в тип string или number его тип XDR, если таковой указан в аннотируемой схеме, анализируется и при необходимости служит основой для решения о преобразовании типов.
Сопоставление типов данных XDR с типами данных XPath
Тип данных XPath узла является производным от типа данных XDR, указанного в схеме, как показано в следующей таблице на примере узла EmployeeID.
Тип данных XDR |
Эквивалентный тип данных XPath |
Использованное преобразование SQL Server |
---|---|---|
Nonebin.base64bin.hex |
Недоступно |
NoneEmployeeID |
boolean |
boolean |
CONVERT(bit, EmployeeID) |
number, int, float,i1, i2, i4, i8,r4, r8ui1, ui2, ui4, ui8 |
число |
CONVERT(float(53), EmployeeID) |
id, idref, idrefsentity, entities, enumerationnotation, nmtoken, nmtokens, chardate, Timedate, Time.tz, string, uri, uuid |
строка |
CONVERT(nvarchar(4000), EmployeeID, 126) |
fixed14.4 |
н/д (в XPath нет типа данных, эквивалентного типу fixed14.4 XDR) |
CONVERT(money, EmployeeID) |
date; |
строка |
LEFT(CONVERT(nvarchar(4000), EmployeeID, 126), 10) |
time; time.tz |
строка |
SUBSTRING(CONVERT(nvarchar(4000), EmployeeID, 126), 1 + CHARINDEX(N'T', CONVERT(nvarchar(4000), EmployeeID, 126)), 24) |
Преобразования даты и времени применяются к значениям, хранящимся в базе данных с использованием типов SQL Serverdatetime или string. Следует заметить, что тип данных SQL Serverdatetime не использует тип timezone и имеет меньшую точность, чем тип данных XML time. Чтобы включить тип данных timezone или более высокую точность, следует хранить данные в SQL Server с использованием типа string.
При преобразовании узла из типа данных XDR в тип данных XPath иногда требуются дополнительные преобразования (из одного типа XPath в другой тип XPath). В качестве примера рассмотрим следующий запрос XPath:
(@m + 3) = 4
Если @m имеет тип XDR fixed14.4, то преобразование из типа XDR в тип XPath проводится следующим образом:
CONVERT(money, m)
В данном случае узел m преобразуется из типа fixed14.4 в тип money. Однако для прибавления 3 требуется дополнительное преобразование:
CONVERT(float(CONVERT(money, m))
Выражение XPath вычисляется следующим образом:
CONVERT(float(CONVERT(money, m)) + CONVERT(float(53), 3) = CONVERT(float(53), 3)
Как показано в следующей таблице, это то же самое преобразование, которое применялось для других выражений XPath (например, литералов или составных выражений).
|
Х неизвестен |
X является string |
X является number |
X является boolean |
string(X) |
CONVERT (nvarchar(4000), X, 126) |
- |
CONVERT (nvarchar(4000), X, 126) |
CASE WHEN X THEN N'true' ELSE N'false' END |
number(X) |
CONVERT (float(53), X) |
CONVERT (float(53), X) |
- |
CASE WHEN X THEN 1 ELSE 0 END |
boolean(X) |
- |
LEN(X) > 0 |
X != 0 |
- |
Примеры
А. Преобразование типа данных в запросе XPath.
В следующем запросе XPath к аннотированной схеме XSD запрос выбирает все узлы Employee, у которых атрибут EmployeeID имеет значение E-1, где "E-" — префикс, указанный с помощью заметки sql:id-prefix.
Employee[@EmployeeID="E-1"]
Предикат в запросе эквивалентен следующему выражению SQL:
N'E-' + CONVERT(nvarchar(4000), Employees.EmployeeID, 126) = N'E-1'
Поскольку EmployeeID принадлежит к одному из типов данных id (idref, idrefs, nmtoken, nmtokens в схеме XSD, EmployeeID преобразуется в тип XPath string с помощью описанных ранее правил преобразования.
CONVERT(nvarchar(4000), Employees.EmployeeID, 126)
К строке добавляется префикс "E-", а результат затем сравнивается с N'E-1'.
Б. Несколько преобразований типов данных в запросе XPath.
Рассмотрим следующий запрос XPath к аннотированной схеме XSD: OrderDetail[@UnitPrice * @OrderQty > 98]
Этот запрос возвращает все дочерние элементы <OrderDetail>, удовлетворяющие предикату @UnitPrice * @OrderQty > 98. Если атрибут UnitPrice в аннотированной схеме аннотирован типом данных fixed14.4, этот предикат эквивалентен следующему выражению SQL:
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice)) * CONVERT(float(53), OrderDetail.OrderQty) > CONVERT(float(53), 98)
В ходе преобразований значений в запросе XPath сначала тип данных XDR преобразуется в тип данных XPath. Поскольку тип данных XSD атрибута UnitPrice — fixed14.4, согласно приведенной выше таблице, сначала применяется следующее преобразование:
CONVERT(money, OrderDetail.UnitPrice))
Поскольку арифметические операторы преобразуют операнды к типу XPath number, применяется второе преобразование (от одного типа данных XPath к другому), в результате которого значение преобразуется к типу float(53) (тип float(53) близок к типу данных XPath number):
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice))
Если у атрибутаOrderQty нет типа данных XSD, то этот атрибут преобразуется к типу XPath number за один шаг:
CONVERT(float(53), OrderDetail.OrderQty)
Подобным же образом значение 98 преобразуется к типу данных XPath number:
CONVERT(float(53), 98)
![]() |
---|
Если используемый в схеме тип данных XSD несовместим с базовым типом SQL Server в базе данных, или нужное преобразование типа данных XPath невозможно выполнить, SQL Server может вернуть ошибку. Например, если атрибут EmployeeID имеет заметку id-prefix, конструкция XPath Employee[@EmployeeID=1] вызовет ошибку, поскольку атрибут EmployeeID имеет заметку id-prefixи его нельзя преобразовать в number. |