商讯信箱
用户名: @
密  码:   注册|忘记密码
登录
个人用户经销商
您的位置:首页 > 技术频道 > 正文

SQL Server 2005 XML最佳实施策略用法

作者:Shankar Pal  2008-01-03
  但是,这不会纠正该错误,因为在每个 XML 实例中都可能出现多个 节点。下面的改写方式将会有效:
SELECT xCol.value('(//author/last-name)[1]', 'nvarchar(50)') LastName FROM T This query returns the value of the first element in each XML instance.
父轴

  如果节点的类型无法确定,则它将成为 anyType,后者不会隐式转换为任何其他类型。在使用父轴(例如,xCol.query('/book/@genre/../price'))进行导航的过程中,尤其会发生这种情况;该父节点类型被确定为 anyType。元素也可能被定义为 XML 架构中的 anyType。在这两种情况下,丢失更为精确的类型信息通常会导致静态类型错误,并且要求将原子值显式转换为它们的特定类型。

  Data()、Text() 和 String() 访问器

  XQuery 具有一个可从节点中提取标量的、类型化值的函数 fn:data(),一个可返回文本节点的节点测试 text(),以及可返回节点的字符串值的函数 fn:string()。它们的用法有时会引起混乱。下面是有关在 SQL Server 2005 中正确使用它们的准则。请考虑 XML 实例 12:

• 非类型化 XML:路径表达式 /age/text() 返回文本节点"12"。函数 fn:data(/age) 返回字符串值"12",fn:string(/age) 也是如此。

• 类型化 XML:对于任何简单的类型化 元素,表达式 /age/text() 都会返回静态错误。另一方面,fn:data(/age) 返回整数 12,而 fn:string(/age) 会产生字符串"12"。

  联合类型的函数和运算符

  由于类型检查,联合类型要求进行认真的处理。以下示例阐述了其中两个问题。

  示例:联合类型上的函数

  请考虑以下联合类型的 的元素定义
<xs:element name="r"> <xs:simpleType> <xs:union memberTypes="xs:int xs:float xs:double"/> </xs:simpleType> </xs:element>
  在 XQuery 上下文中,"average"函数 fn:avg (//r) 会返回静态错误,因为 XQuery 编译器无法对 fn:avg() 的参数中元素的不同类型(xs:int、xs:float 或 xs:double)的值求和。为解决该问题,请将函数调用改写为 fn:avg(for $r in //r return $r cast as xs:double ?)。
 
  示例:联合类型上的运算符

  加法运算"+"要求精确的操作数类型,以至于表达式 (//r)[1] + 1 对上述元素 的类型定义返回静态错误。可以解决该问题的一种改写方式是 (//r)[1] cast as xs:int?+1,其中"?"表示具体取值 0 或 1。SQL Server 2005 要求带有"?"的"cast as",因为任何转换都会由于运行时错误而产生空序列。

  Value()、Nodes() 和 OpenXML()

  可以在 SELECT 子句中对 XML 数据类型使用多个 value() 方法来生成提取值的行集。nodes() 方法会为所选的每个节点生成一个内部引用,以用于进一步查询。当行集具有多个列,并且用于生成行集的路径表达式可能比较复杂时,将 nodes() 和 value() 方法组合使用可能会更为有效。

  nodes() 方法可生成特殊 XML 数据类型的实例,每个实例都将其上下文设置为所选的不同节点。此类 XML 实例支持 query()、value()、nodes() 和 exist() 方法,并且可用在 count(*) 聚合中。所有其他用法都会导致错误。

  示例:nodes() 的用法

  假设您希望提取名字不是"David"的作者的姓名,作为由两个列(FirstName 和 LastName)组成的行集。使用 nodes() 和 value() 方法可以达到此目的,如下所示:
SELECT nref.value('first-name[1]', 'nvarchar(50)') FirstName, nref.value('last-name[1]', 'nvarchar(50)') LastName FROM T CROSS APPLY xCol.nodes('//author') AS R(nref) WHERE nref.exist('.[first-name != "David"]') = 1
  在该示例中,nodes('//author') 会生成一个由对每个 XML 实例的 元素的引用组成的行集。通过相对于这些引用对 value() 方法求值,可以获取作者的名字和姓氏。

  SQL Server 2000 提供了使用 OpenXml() 从 XML 实例生成行集的功能。您可以指定行集的关系架构,并指定 XML 实例内部的值如何映射到该行集中的列。

  示例:对 XML 数据类型使用 OpenXml()

  我们可以像下面显示的那样,使用 OpenXml() 来改写上一示例中的查询,方法是:创建一个游标,将各个 XML 实例读入一个 XML 变量,然后向其应用 OpenXML():
DECLARE name_cursor CURSOR FOR SELECT xCol FROM T OPEN name_cursor DECLARE @xmlVal XML DECLARE @idoc int FETCH NEXT FROM name_cursor INTO @xmlVal WHILE (@@FETCH_STATUS = 0) BEGIN EXEC sp_xml_preparedocument @idoc OUTPUT, @xmlVal SELECT * FROM OPENXML (@idoc, '//author') WITH (FirstName varchar(50) 'first-name', LastName varchar(50) 'last-name') R WHERE R.FirstName != 'David' EXEC sp_xml_removedocument @idoc FETCH NEXT FROM name_cursor INTO @xmlVal END CLOSE name_cursor DEALLOCATE name_cursor
  penXml() 会创建内存中的表示形式,并使用工作表而不是查询处理器。它依赖于 MSXML 3.0 的 XPath 1.0 处理器而不是 XQuery 引擎。工作表不在对 OpenXml() 的多个调用中共享(即使是在同一个 XML 实例上)。这限制了它的可伸缩性。在未指定 WITH 子句时,可以通过 OpenXml() 来访问 XML 数据的边缘表格式。而且,还可以通过它使用 XML 值在单独的"溢出"列中的剩余部分。

  nodes() 和 value() 函数的组合可以有效地使用 XML 索引。因此,这一组合可以表现出比 OpenXml 更高的可伸缩性。

1 2 3
【内容导航】
第1页: 概述 第2页: 第2页
第3页: 第3页
©版权所有。未经许可,不得转载。
[责任编辑:nancy]
[an error occurred while processing this directive]