XPath 数据类型 (SQLXML 4.0)
适用于: SQL Server
Azure SQL 数据库
Microsoft SQL Server、XPath 和 XML 架构(XSD)具有截然不同的数据类型。 例如,XPath 没有整数或日期数据类型,但 SQL Server 和 XSD 有许多。 XSD 对时间值使用纳秒精度,SQL Server 最多使用 1/300 秒精度。 因此,将一种数据类型映射到另一种数据类型并不是始终可行的。 有关将 SQL Server 数据类型映射到 XSD 数据类型的详细信息,请参阅数据类型强制和 sql:数据类型注释(SQLXML 4.0)。
XPath 有三种数据类型: 字符串、 数字和 布尔值。 数字数据类型始终是 IEEE 754 双精度浮点。 SQL Serverfloat(53) 数据类型最接近 XPath 编号。 但是, float(53) 并不完全是 IEEE 754。 例如,NaN(非数字)和 infinity 均未使用。 尝试将非数字字符串 转换为数字 ,并尝试除以零会导致错误。
XPath 转换
在您使用 OrderDetail[@UnitPrice > "10.0"]
之类的 XPath 查询时,隐式和显式数据类型转换可能会对查询的意义产生细微的变化。 因此,理解 XPath 数据类型的实现方式十分重要。 可以在 W3C 网站 http://www.w3.org/TR/1999/PR-xpath-19991008.html中找到 XPath 语言规范(XPath)版本 1.0 W3C 建议建议 1999 年 10 月 8 日。
XPath 运算符分为四个类别:
布尔运算符(and、or)
关系运算符 (<, , <>=, >=)
相等运算符(=、!=)
算术运算符(+、-、*、div、mod)
每个运算符类别都以不同方式转换其操作数。 XPath 运算符根据需要隐式转换其操作数。 算术运算符将其操作数转换为 数字,并生成数字值。 布尔运算符将其操作数转换为 布尔值,并生成布尔值。 关系运算符和相等运算符产生布尔值。 但是,根据其操作数的原始数据类型,这两种运算符具有不同的转换规则,如下表所示。
操作数 | 关系运算符 | 相等运算符 |
---|---|---|
这两种操作数均为节点集。 | 如果仅在一个集中有一个节点并且第二个集中有一个节点,以便其 字符串 值的比较为 TRUE 时,才为 TRUE。 | 相同。 |
一个是节点集,另一个是 字符串。 | 如果仅在节点集中存在节点,以便转换为数字时,将其与转换为数字的字符串的比较为 TRUE,则为 TRUE。 | 如果仅在节点集中有节点,以便转换为 字符串时,才会将其与 字符串 进行比较,则为 TRUE。 |
一个是节点集,另一个是 数字。 | 如果仅在节点集中存在节点,以便转换为 数字时,其与 数字 的比较为 TRUE,则为 TRUE。 | 相同。 |
一个是节点集,另一个是 布尔值。 | 如果仅在节点集中存在节点,以便转换为布尔值,然后转换为数字时,将其与转换为数字的布尔值进行比较为 TRUE,则为 TRUE。 | 如果仅在节点集中存在节点,以便转换为 布尔值时,该节点与 布尔 值的比较为 TRUE,则为 TRUE。 |
两者均不是节点集。 | 将两个操作数转换为 数字 ,然后进行比较。 | 将两个操作数均转换为常见类型,然后进行比较。 如果任一是布尔值,则转换为布尔值;如果任一为数字,则转换为布尔值;否则,请转换为字符串。 |
注意
由于 XPath 关系运算符始终将其操作数转换为 数字, 因此无法进行字符串 比较。 为了包含日期比较,SQL Server 2000 向 XPath 规范提供此变体:当关系运算符将字符串与字符串进行比较、将节点设置为字符串或字符串值节点集设置为字符串值节点集时,将执行字符串比较(而不是数字比较)。
节点集转换
节点集转换并非始终都是直观的。 节点集通过仅获取集中第一个 节点的字符串值转换为字符串 。 节点集通过将节点集转换为数字,然后将其转换为字符串,然后将字符串转换为数字。 通过测试节点集是否存在,将节点集转换为 布尔 值。
注意
SQL Server 不对节点集执行位置选择:例如,XPath 查询 Customer[3]
表示第三个客户;SQL Server 不支持这种类型的位置选择。 因此,不会实现 XPath 规范中所述的 node-set-to-string 或 node-set-to-number 转换。 无论 XPath 规范指定“first”语义,SQL Server 都使用“any”语义。 例如,根据 W3C XPath 规范,XPath 查询Order[OrderDetail/@UnitPrice > 10.0]
选择具有大于 10.0 的 UnitPrice 的第一个 OrderDetail 的订单。 在 SQL Server 中,此 XPath 查询选择具有大于 10.0 的 UnitPrice 的任何 OrderDetail 的订单。
转换为 布尔 值会生成存在测试;因此,XPath 查询 Products[@Discontinued=true()]
相当于 SQL 表达式“Products.Discontinued is not null”,而不是 SQL 表达式“Products.Discontinued = 1”。 若要使查询等效于后一个 SQL 表达式,请先将节点集转换为非布尔 类型,例如 数字。 例如,Products[number(@Discontinued) = true()]
。
因为如果运算符对于节点集中任一节点为 TRUE,则大多数运算符均定义为 TRUE;所以,在节点集为空时,这些运算的计算结果始终为 FALSE。 因此,如果 A 为空,则 A = B
和 A != B
均为 FALSE,并且 not(A=B)
和 not(A!=B)
均为 TRUE。
通常,如果数据库中该列的值不 为 null,则存在映射到列的属性或元素。 如果元素的任何子集存在,则映射到行的元素将存在。
注意
使用 is-constant 批注的元素始终存在。 因此,不能对 is-constant 元素使用 XPath 谓词。
当节点集转换为 字符串 或 数字时,其 XDR 类型(如果有)在批注架构中检查,并且该类型用于确定所需的转换。
将 XDR 数据类型映射到 XPath 数据类型
节点的 XPath 数据类型派生自架构中的 XDR 数据类型,如下表所示(node EmployeeID 用于说明目的)。
XDR 数据类型 | 等效 XPath 数据类型 |
使用的 SQL Server 转换 |
---|---|---|
Nonebin.base64bin.hex | 空值 | NoneEmployeeID |
boolean | boolean | CONVERT(bit, EmployeeID) |
number、int、float、i1、i2、i4、i8、r4、r8、ui1、ui2、ui4、ui8 | 数字 | CONVERT(float(53), EmployeeID) |
id、idref、idrefsentity、entities、enumerationnotation、nmtoken、nmtokens、chardate、Timedate、Time.tz、string、uri、uuid | string | CONVERT(nvarchar(4000), EmployeeID, 126) |
fixed14.4 | 无(在 XPath 中没有等效于 fixed14.4 XDR 数据类型的数据类型) | CONVERT(money, EmployeeID) |
date | string | LEFT(CONVERT(nvarchar(4000), EmployeeID, 126), 10) |
time time.tz |
string | SUBSTRING(CONVERT(nvarchar(4000), EmployeeID, 126), 1 + CHARINDEX(N'T', CONVERT(nvarchar(4000), EmployeeID, 126)), 24) |
日期和时间转换旨在使值是使用 SQL Server日期时间 数据类型还是 字符串存储在数据库中。 请注意,SQL Server日期/时间 数据类型不使用 时区 ,精度小于 XML 时间 数据类型。 若要包括时区数据类型或其他精度,请使用字符串类型将数据存储在 SQL Server 中。
在某一节点从其 XDR 数据类型转换为 XPath 数据类型时,有时候可能需要执行附加的转换(从一个 XPath 数据类型转换为另一个 XPath 数据类型)。 例如,请考虑下面的 XPath 查询:
(@m + 3) = 4
如果 @m 为固定的 14.4 XDR 数据类型,则使用以下命令完成从 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 未知 | X 为字符串 | X 为数字 | X 为布尔值 | |
---|---|---|---|---|
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 |
布尔值(X) | - | LEN(X) > 0 | X != 0 | - |
示例
A. 在 XPath 查询中转换数据类型
在针对带批注的 XSD 架构指定的以下 XPath 查询中,查询选择所有 Employee 节点,其 EmployeeID 属性值为 E-1,其中“E-”是使用 sql:id 前缀注释指定的前缀。
Employee[@EmployeeID="E-1"]
该查询中的谓词等效于 SQL 表达式:
N'E-' + CONVERT(nvarchar(4000), Employees.EmployeeID, 126) = N'E-1'
由于 EmployeeID 是 XSD 架构中的 ID(idref、idrefs、nmtoken、nmtokens 等)数据类型值之一,因此 EmployeeID 使用前面所述的转换规则转换为字符串 XPath 数据类型。
CONVERT(nvarchar(4000), Employees.EmployeeID, 126)
“E-”前缀将添加到字符串,然后结果将与 N'E-1'
进行比较。
B. 在 XPath 查询中执行若干数据类型转换
考虑以下根据带批注的 XSD 架构指定的 XPath 查询:OrderDetail[@UnitPrice * @OrderQty > 98]
此 XPath 查询返回满足谓词@UnitPrice * @OrderQty > 98
的所有 <OrderDetail> 元素。 如果在带批注的架构中使用固定的 14.4 数据类型批注 UnitPrice,则此谓词等效于 SQL 表达式:
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice)) * CONVERT(float(53), OrderDetail.OrderQty) > CONVERT(float(53), 98)
在 XPath 查询中转换值时,第一个转换将 XDR 数据类型转换为 XPath 数据类型。 由于 UnitPrice 的 XSD 数据类型是固定的 14.4,如上表所述,这是使用的第一个转换:
CONVERT(money, OrderDetail.UnitPrice))
由于算术运算符将其操作数 转换为数字 XPath 数据类型,因此将应用第二个转换(从一个 XPath 数据类型转换为 另一个 XPath 数据类型),其中值转换为 float(53) (float(53) 接近 XPath 数字 数据类型):
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice))
假设 OrderQty 属性没有 XSD 数据类型,则 OrderQty 在单个转换中转换为数字 XPath 数据类型:
CONVERT(float(53), OrderDetail.OrderQty)
同样,值 98 转换为 数字 XPath 数据类型:
CONVERT(float(53), 98)
注意
如果架构中使用的 XSD 数据类型与数据库中的基础 SQL Server 数据类型不兼容,或者执行不可能的 XPath 数据类型转换,SQL Server 可能会返回错误。 例如,如果使用 ID 前缀批注对 EmployeeID 属性进行批注,则 XPath Employee[@EmployeeID=1]
将生成错误,因为 EmployeeID 具有 ID 前缀批注,无法转换为数字。