FOR XML 子句的使用准则
FOR XML 子句可以用在顶级查询和子查询中。顶级 FOR XML 子句只能用在 SELECT 语句中。而在子查询中,FOR XML 可以用在 INSERT、UPDATE 和 DELETE 语句中。它还可以用在赋值语句中。例如:
DECLARE @x xml
SET @x = (SELECT *
FROM Sales.Customer
FOR XML AUTO, TYPE)
SELECT @x
请注意,TYPE 指令将返回 xml 类型作为查询结果。如果未添加 type 指令,则将返回 nvarchar(max) 作为 FOR XML 查询结果。然后,此结果将被转换为 xml 并分配给 xml 类型变量。
FOR XML 子句受制于下列限制:
对于任何与 COMPUTE BY 或 FOR BROWSE 子句一起使用的选择,FOR XML 均无效。例如,以下语句将会导致错误:
SELECT TOP 5 SalesOrderID, UnitPrice FROM Sales.SalesOrderDetail ORDER BY SalesOrderID COMPUTE SUM(UnitPrice) BY SalesOrderID FOR XML AUTO
不带 TYPE 指令的顶级 FOR XML 不能与游标一起使用。
如果带 FOR XML 子句的 SELECT 语句在查询中指定了一个由四部分组成的名称,则在本地计算机上执行查询时,所得 XML 文档中将不返回该服务器名称。但在网络服务器上执行查询时,将返回这个由四部分组成的服务器名称。
例如,请考虑下面的查询:SELECT TOP 1 LastName FROM ServerName.AdventureWorks.Person.Contact FOR XML AUTO
如果
ServerName
是本地服务器,则此查询将返回以下结果:<AdventureWorks.Person.Contact LastName="Achong" />
如果
ServerName
是网络服务器,此查询将返回以下结果:<ServerName.AdventureWorks.Person.Contact LastName="Achong" />
通过指定以下别名可以避免这种潜在的二义性:
SELECT TOP 1 LastName FROM ServerName.AdventureWorks.Person.Contact x FOR XML AUTO
此查询将返回以下结果:
<x LastName="Achong"/>
另外,通过将无效字符转换为转义数字实体编码,将含有在 XML 名称中无效的字符(例如空格)的 SQL Server 名称转换为了 XML 名称。
只有两个非字母字符可以出现在 XML 名称中:冒号 (:) 和下划线 (_)。由于冒号 (:) 已经保留给命名空间,因此下划线 (_) 被选作转义符。以下是用于编码的转义规则:
根据 XML 1.0 规范,任何不是有效的 XML 名称字符的 UCS-2 字符都将被转义为 _xHHHH_。HHHH 代表该字符对应的四位十六进制 UCS-2 代码,最重要的位排在最前面。例如,表名 Order Details 被编码为 Order_x0020_Details。
不适合 UCS-2 领域的字符(介于 U+00010000 到 U+0010FFFF 之间的附加 UCS-4 字符)均被编码为 _xHHHHHHHH_。如果处在 SQL Server 2000 向后兼容模式下,则 HHHHHHHH 代表该字符对应的八位十六进制 UCS-4 编码。否则,字符将被编码为 _xHHHHHH_,以便符合 SQL-2003 标准。
下划线字符不需要进行转义,除非其后为字符 x。例如,表名 Order_Details 不进行编码。
标识符中的冒号不进行转义,这样 FOR XML 查询就可以生成命名空间元素和属性名称。例如,下面的查询将生成其名称中包含冒号的命名空间属性:
SELECT 'namespace-urn' as 'xmlns:namespace', 1 as 'namespace:a' FOR XML RAW
此查询产生以下结果:
<row xmlns:namespace="namespace-urn" namespace:a="1"/>
请注意,建议使用 WITH XMLNAMESPACES 来添加 XML 命名空间。
在 SELECT 查询中,将任一列转换为二进制大型对象 (BLOB) 将使该列成为临时实体(它将丢失与其相关联的表名和列名)。这将使 AUTO 模式的查询生成错误,因为它不知道将该值放在 XML 层次结构中的什么位置。例如:
CREATE TABLE MyTable (Col1 int PRIMARY KEY, Col2 binary) INSERT INTO MyTable VALUES (1, 0x7)
由于会转换为二进制大型对象 (BLOB),因此以下查询将产生错误:
SELECT Col1, CAST(Col2 as image) as Col2 FROM MyTable FOR XML AUTO
解决方案是将 BINARY BASE64 选项添加到 FOR XML 子句中。如果删除转换,此查询将生成预期的结果:
SELECT Col1, Col2 FROM MyTable FOR XML AUTO
结果如下:
<MyTable Col1="1" Col2="dbobject/MyTable[@Col1='1']/@Col2" />
在 SQL Server 2000 中,FOR XML 输出可以包含无效的 XML 字符。例如,使用十六进制值 7 作为格式字符,但是另一方面,该值通常不能作为输出中的文本来查看。现在,当在没有使用 TYPE 指令的 FOR XML 查询内返回这些字符时,SQL Server 2005 将实体化这些字符。
尽管 XML 1.0 一致性分析器不管这些字符是否被实体化都会生成分析错误,但是经过实体化的格式更符合 XML 1.1。经过实体化的格式还会更符合 XML 标准的未来版本。此外,它使得调试变得更加简单,因为无效字符的码位将变为可见的。
对于 XML 工具的用户,不需要任何解决方法,因为无论怎样,在数据流中出现无效字符的位置,XML 分析器都将失败。如果使用非 XML 工具,则此更改会要求您更新编程逻辑以便将这些字符作为实体化的值来搜索。在 SQL Server 2005 中,已在 FOR XML 查询中以不同的方式实体化下列空格字符,以使它们在整个往返中都存在:
- 在元素内容和属性中:hex(0D)(回车符)
- 在属性内容中:hex(09)(选项卡)、hex(0A)(换行符)
如果应用程序最初用于处理 SQL Server 2000 输出(在其中规范化了这些字符),则这可能会影响该应用程序。现在,SQL Server 2005 输出将保留这些字符,并且分析器将不再规范化它们。