使用XML数据类型方法的指南

本主题适用于:  SQL Server (starting with 2012) Azure SQL Database Azure SQL Data Warehouse  Parallel Data Warehouse

本主题讲解了使用xml数据类型方法的指南。

PRINT语句

xml数据类型方法不能用在PRINT语句中,如下面的示例所示。xml数据类型方法被视为子查询,而子查询不允许在PRINT语句中。因此,下面的示例返回一个错误:

DECLARE @x xml
SET @x = '<root>Hello</root>'
PRINT @x.value('/root[1]', 'varchar(20)') -- will not work because this is treated as a subquery (select top 1 col from table)

一个解决方案是先把value()方法的结果赋给一个xml类型的变量,然后在查询中指定变量。

DECLARE @x xml
DECLARE @c varchar(max)
SET @x = '<root>Hello</root>'
SET @c = @x.value('/root[1]', 'varchar(11)')
PRINT @c

GROUP BY子句

xml数据类型方法被内部视为子查询。因为GROUP BY要求一个标量,不允许聚合和子查询,所以你不能在GROUP BY子句中指定xml数据类型。一个解决方案是调用一个用户定义的函数,函数内使用XML方法。

报告错误

Msg errorNumber, Level levelNumber, State stateNumber:
XQuery [database.table.method]: description_of_error

举个例子:

Msg 2396, Level 16, State 1:
XQuery [xmldb_test.xmlcol.query()]: Attribute may not appear outside of an element

单例模型检查

如果编译器不能确定在运行时是否确保需要单例模型的本地步骤、函数参数以及操作符,操作的是一个单例模型,将返回一个错误。非类型化数据经常出现这个问题。举个例子,查找一个属性需要一个单例模型父元素。一个序数词选择了一个单一父节点是满足的。对node()-value()组合的估值,来提取属性值,可能不需要序数规范文档。下个示例显示了它。

示例:已知的单例模型

在此示例中,nodes()方法为每个<book>元素生成了一个分开的行。value()方法在一个<book>节点上估值,提取出@genre的值,它是一个属性,是一个单例模型。

SELECT nref.value('@genre', 'varchar(max)') LastName
FROM   T CROSS APPLY xCol.nodes('//book') AS R(nref)

XML架构用于类型化XML的类型检查。如果在XML架构中,一个节点被指定为一个单例模型,编译器将使用那个信息,不会发生错误。否则,一个选择单个节点的序数词是必不可少的。特别是,使用“后代或自身轴(//)”,比如说在/book//title中,松散的单例模型基数推断出<title> 元素,甚至哪怕XML架构指定它是如此。因此,你必须重写它为(/book//title/)[1]。

记住//first-name[1]和(//first-name)[1]这两者在类型检查方面的区别很重要:前者返回<first-name>节点的序列,每个节点都是同辈元素中最左边的<first-name>节点。后者依XML实例的顺序,返回文档中第一个单例模型<first-name>节点。

示例:使用value()

下面的查询发生在一个非类型化的XML列上,产生一个静态的、汇编的错误。这是因为value()期待一个单例模型,作为第一个参数,而编译器不能确定在运行时是否只出现一个<last-name>节点:

SELECT xCol.value('//author/last-name', 'nvarchar(50)') LastName
FROM   T

下面是你可以考虑使用的解决方案:

SELECT xCol.value('//author/last-name[1]', 'nvarchar(50)') LastName
FROM   T

然而,该解决方案不能解决错误,因为每个实例中可能出现多个<author>节点。以下的重写才能起作用:

SELECT xCol.value('(//author/last-name/text())[1]', 'nvarchar(50)') LastName
FROM   T

该查询返回每个XML实例中第一个<last-name>的值。

如果你喜欢这篇文章,敬请给站长打赏↑

除特别注明外,本站所有文章均为本站站长原译,转载请注明出处。