XPath 数据类型 (SQLXML 4.0)
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 Server float (53) 数据类型最接近 XPath 编号。 但是, float (53) 并不完全是 IEEE 754。 例如,NaN(非数字)和 infinity 均未使用。 尝试将非数值字符串转换为 数字 并尝试除以零会导致错误。
XPath 转换
在您使用 OrderDetail[@UnitPrice > "10.0"]
之类的 XPath 查询时,隐式和显式数据类型转换可能会对查询的意义产生细微的变化。 因此,理解 XPath 数据类型的实现方式十分重要。 XPath 语言规范 XML 路径语言 (XPath) 版本 1.0 W3C 建议 1999 年 10 月 8 日,可在 W3C 网站上 http://www.w3.org/TR/1999/PR-xpath-19991008.html找到。
XPath 运算符分为四个类别:
布尔运算符(and、or)
关系运算符 (<、 >、 <=、 >=)
相等运算符(=、!=)
算术运算符(+、-、*、div、mod)
每个运算符类别都以不同方式转换其操作数。 XPath 运算符根据需要隐式转换其操作数。 算术运算符将其操作数转换为 数字,并生成数字值。 布尔运算符将其操作数转换为 布尔值,并生成布尔值。 关系运算符和相等运算符产生布尔值。 但是,根据其操作数的原始数据类型,这两种运算符具有不同的转换规则,如下表所示。
操作数 | 关系运算符 | 相等运算符 |
---|---|---|
这两种操作数均为节点集。 | 如果且仅当一个集中有一个节点,第二个集中有一个节点,以便其 字符串 值的比较为 TRUE 时,才为 TRUE。 | 相同。 |
一个是节点集,另一个是 字符串。 | 如果且仅当节点集中有一个节点时,该节点与转换为数字的字符串的比较为 TRUE,则为 TRUE。 | 如果且仅当节点集中有一个节点时,该节点与字符串的比较为 TRUE,则为 TRUE。 |
一个是节点集,另一个是 数字。 | 如果且仅当节点集中有一个节点时,它与数字的比较为 TRUE,则为 TRUE。 | 相同。 |
一个是节点集,另一个是 布尔值。 | 如果且仅当节点集中有一个节点时,当转换为布尔值,然后转换为 number 时,该节点与转换为数字的布尔值比较为 TRUE,则为 TRUE。 | 如果且仅当节点集中有一个节点时,当转换为 布尔值时,该节点与 布尔 值的比较为 TRUE,则为 TRUE。 |
两者均不是节点集。 | 将这两个操作数转换为 数字 ,然后比较。 | 将两个操作数均转换为常见类型,然后进行比较。 如果任一为 布尔值 ,则转换为 布尔值;如果其中一个为 number ,则转换为 number;否则,请转换为 字符串。 |
注意
由于 XPath 关系运算符始终将其操作数转换为 数字,因此无法进行 字符串 比较。 为了包含日期比较,SQL Server 2000 提供了 XPath 规范的此变体:当关系运算符将字符串与字符串、节点集与字符串或字符串值 node-set 进行比较时,将执行字符串比较 (而不是数字比较) 。
节点集转换
节点集转换并非始终都是直观的。 节点集通过仅获取 集中 第一个节点的字符串值来转换为字符串。 通过将节点集转换为字符串,然后将字符串转换为数字,将节点集转换为数字。 通过测试节点集是否存在,将节点集转换为 布尔值 。
注意
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]
选择具有 UnitPrice 大于 10.0 的第一个 OrderDetail 的订单。 在SQL Server,此 XPath 查询选择具有 UnitPrice 大于 10.0 的任何 OrderDetail 的订单。
转换为 布尔值 会生成存在测试;因此,XPath 查询 Products[@Discontinued=true()]
等效于 SQL 表达式“Products.Discontinued 不是 null”,而不是 SQL 表达式“Products.Discontinued = 1”。 若要使查询等效于后一个 SQL 表达式,请先将 node-set 转换为非布尔 类型,例如 number。 例如 Products[number(@Discontinued) = true()]
。
因为如果运算符对于节点集中任一节点为 TRUE,则大多数运算符均定义为 TRUE;所以,在节点集为空时,这些运算的计算结果始终为 FALSE。 因此,如果 A 为空,则 A = B
和 A != B
均为 FALSE,并且 not(A=B)
和 not(A!=B)
均为 TRUE。
通常,如果数据库中该列的值不 为 null,则存在映射到列的属性或元素。 如果元素的任何子集存在,则映射到行的元素将存在。
注意
使用 is-constant 批注的元素始终存在。 因此,XPath 谓词不能用于 is-constant 元素。
当节点集转换为 字符串 或 数字时,如果批注架构中检查了任何) ,则其 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、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 datetime 数据类型还是字符串存储在数据库中,日期和时间转换都适合工作。 请注意,SQL Server datetime 数据类型不使用时区,其精度小于 XML 时间数据类型。 若要包含时区数据类型或其他精度,请使用字符串类型将数据存储在SQL Server中。
在某一节点从其 XDR 数据类型转换为 XPath 数据类型时,有时候可能需要执行附加的转换(从一个 XPath 数据类型转换为另一个 XPath 数据类型)。 例如,请考虑下面的 XPath 查询:
(@m + 3) = 4
如果 @m 为 fixed14.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 |
boolean(X) | - | LEN (X) > 0 | X != 0 | - |
示例
A. 在 XPath 查询中转换数据类型
在针对带批注的 XSD 架构指定的以下 XPath 查询中,该查询选择 EmployeeID 属性值为 E-1 的所有 Employee 节点,其中“E-”是使用 sql:id-prefix 注释指定的前缀。
Employee[@EmployeeID="E-1"]
该查询中的谓词等效于 SQL 表达式:
N'E-' + CONVERT(nvarchar(4000), Employees.EmployeeID, 126) = N'E-1'
由于 EmployeeID是 (idref、idrefs、nmtokens、nmtokens 等 id) XSD 架构中的数据类型值之一,因此 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> 元素。 如果在批注架构中使用 fixed14.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 number 数据类型) :
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可能会返回错误。 例如,如果 EmployeeID 属性使用 id 前缀 批注进行批注,XPath Employee[@EmployeeID=1]
将生成错误,因为 EmployeeID 具有 ID 前缀 注释,无法转换为 数字。
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈