SQL Server 2005中的新XML功能


  本文标签:SQL Server XML

  目前,很多开发人员都将SQL Server 2005作为应用程序数据库  。这其中的原因是多方面的,例如开发习惯、功能强大、易于上手、对于既有开发技术的支持等  。为了帮助广大读者熟悉SQL Server 2005,本文重点对SQL Server 2005提供的新XML功能进行讲解  。在讲解之前,首先了解有关的基本概念  。

  由于SQL Server 2000是在服务器中利用BLOB字段存储XML文本,所以不能以原格式真正使用或者引用服务器中的XML  。为了使用SQL Server 2000中的XML,必须将XML抽取到应用程序层,然后使用XML语法分析程序或者文档对象模型来使用数据  。

  SQL Server 2005的XML数据类型避免了这种限制,因为该类型被实现为最好原数据类型  。新的数据类型可使SQL Server如同理解整型或者字符串数据那样相同的方式理解XML数据  。使用XML数据类型可创建仅存储XML,或者存储XML和关系型数据的表  。这种灵活性使得开发人员对结构化数据使用关系型模型,同时利用XML的半结构化数据增强该数据  。当以XML数据类型列存储XML值时,有两种选择:一种是使用类型化列,在这种类型列中存储的XML数据使用XML架构集合来确保有效性  。另一种是非类型化列:在这种类型列中,只要XML数据格式良好,则能够插入任何类型的XML数据  。

  为帮助开发人员最有效的结合半结构化和关系型数据,SQL Server 2005的XML数据类型支持多个实现查询和修改XML数据的内建方法  。这些方法可接受XQuery,它是新兴的W3C标准语言,同时还包括XPath 2.0  。开发人员可以将对于XML数据类型方法的查询调用与创建查询,返回关系型和XML数据的标准T-SQL一起使用  。

  除了XML数据类型以外,FOR XML和OpenXML功能在SQL Server 2005中也得到了扩展  。这些功能共同支持XQuery,这样SQL Server 2005就能够通过一个功能强大的平台来实现利用半结构化数据开发富应用程序,以及非结构化数据的管理  。使用所有这些添加的功能,开发人员对于数据存储和应用程序开发则有了更多的选择  。下面首先介绍SQL Server 2005中的FOR XML功能  。

  1、SQL Server 2005中的FOR XML功能

  SQL Server 2000为SELECT语句引入了FOR XML子句  。FOR XML子句能够将SELECT语句返回的关系型行集合聚合为XML数据  。如下所示,服务器中的FOR XML支持三种模式,这些模式提供了不同的转换方式:

  RAW:RAW模式为每行都生成名为row的单个元素  。
AUTO:该模式根据衍生关系和SELECT语句中数据的顺序,推断出一种简单的,一个元素名称代表一个级别的层次  。
EXPLICIT:该模式通过设置单个的SQL查询,能够生成专用的可映射为几乎所有XML结构的行集合格式  。

  为了高效生成大型文档,所有这三个模式都设计用于生成能够以流方式传输的XML数据  。虽然EXPLICIT模式能够成功实现格式化目标,但是生成行集合的格式化SQL表达式很复杂  。使用SQL Server 2005后,这种与FOR XML模式相关的复杂性在很大范围内得以简化  。除此之外,FOR XML查询还集成了XML数据类型  。

  如果执行任何类型的XML查询(例如,SELECT * FROM HumanResources.Employee FOR XML AUTO),那么开发人员将注意到,除了在结果中添加了下划线不同之外,在SQL Server Management Studio中看到的结果看起来非常类似于SQL Server 2000 Query Analyzer中的XML结果  。这意味着可以单击这些结果  。单击结果将显示良好的XML视图,从而便于查看XML结果  。

  下面将介绍SQL Server 2005添加的FOR XML子句的新扩展功能  。

  FOR XML子句使用引入的XML数据类型能够使用新的TYPE指令直接生成XML实例  。例如,以下查询以XML数据类型实例返回Employee元素,而不是nvarchar(max)实例,后者是在不使用TYPE指令的情况下的输出:

  SELECT * FROM HumanResources.Employee as Employee FOR XML AUTO, TYPE

  以上结果保证符合XML数据类型提供的格式良好的约束  。由于结果是XML数据类型实例,所以还可以使用XQuery表达式查询和整理结果  。例如,以下表达式将获取的员工头衔添加到新元素中:

  
SELECT (SELECT * FROM HumanResources.Employee as Employee FOR XML AUTO, TYPE).query( { for $c in /Employee return })    上面的查询将生成如下输出:
------ ------

  由于FOR XML查询返回可赋予的值,所以FOR XML查询结果能够赋值给XML变量或者插入XML列中:

  /* 将FOR XML输出赋值给变量 */ DECLARE @Employee XML; SET @Employee = (SELECT * FROM HumanResources.Employee FOR XML AUTO, TYPE) CREATE TABLE Employee_New (EmployeeID int, XmlData XML) /* 将FOR XML输出赋值给列 */ INSERT INTO Employee_New SELECT 1, @Employee

  在这些语句中,开发人员将FOR XML查询结果赋值给一个XML数据类型变量,然后利用该变量将值插入Employee_New表中  。

  2、利用ADO.NET执行FOR XML查询

  为了通过FOR XML查询直接从SQL Server返回XML流,需要使用SqlCommand对象的ExecuteXmlReader()方法  。ExecuteXmlReader()方法可返回SqlCommand设置的查询结果生成的XmlReader对象  。示例1说明了使用ExecuteXmlReader()方法查询AdventureWorks数据库的DatabaseLog表  。

  示例1:使用ExecuteXmlReader方法执行FOR XML查询

  <%@ Page Language="C#" ValidateRequest="false" %><%@ Import Namespace="System.Data" %><%@ Import Namespace="System.Data.SqlClient" %><%@ Import Namespace="System.Data.Sql" %><%@ Import Namespace="System.Xml" %><%@ Import Namespace="System.Web.Configuration" %><%@ Import Namespace="System.Data.SqlTypes" %> http://www.w3.org/1999/xhtml">


示例1首先打开数据库连接,该数据库由作为参数的连接字符串设置:

  

  using (SqlConnection connection = new SqlConnection(connectionString))

  此后,创建SqlCommand对象实例,接着设置其属性:

  SqlCommand command = connection.CreateCommand(); command.CommandText = "SELECT DatabaseLogID, XmlEvent FROM " + " DatabaseLog WHERE DatabaseLogID = " + ID.ToString() + " FOR XML AUTO, ROOT(DatabaseLogs), ELEMENTS”;

  此时,通过调用SqlCommand对象的ExecuteXmlReader()方法来执行实际查询:
XmlReader reader = command.ExecuteXmlReader();

  然后,将XmlReader对象加载到XmlDocument,以便随后处理:

  XmlDocument doc = new XmlDocument(); // 将XmlReader对象加载到XmlDocument doc.Load(reader);

  当将XML加载到XmlDocument中后,接着会在序列中显示Complete XML,DatabaseLogID和XmlEvent列值  。

  读者已经了解了使用ExecuteXmlReader()同步执行FOR XML查询的方法  。虽然这种方法可用,但是有时候从可扩展性和吞吐量的角度出发,可能希望异步执行查询  。幸运的是,ADO.NET 2.0提供了一个异步执行SQL命令的新功能  。使用这种新功能,开发人员可针对SQL Server数据库异步执行命令,而不用等命令执行完成  。该功能在客户端应用程序(例如Windows Forms应用程序或者ASP.NET应用程序)完成需要长时间执行的数据库命令的情况下,非常方便  。通过实现该功能,能够改进应用程序的整体性能和响应速度  。下面将介绍使用ADO.NET 2.0异步功能执行FOR XML查询的方法,首先讲解的是异步执行FOR XML查询的步骤  。

  异步执行需要BeginXXX和EndXXX这样对应的方法  。BeginXXX方法启动异步操作,同时立刻引用一个实现IAsyncResult接口的对象  。客户端代码需要访问该接口,以便监视异步操作的过程  。当异步操作完成时,可调用EndXXX方法来获取结果,同时清除用于支持异步调用的资源  。

  为使用BeginXXX和EndXXX方法实现异步调用,通常可使用四种常见方法  。在所有的情况下,调用BeginXXX方法来初始化调用  。此后,执行以下四个任务之一:

  完成一些工作之后,接着调用EndXXX方法  。如果异步操作未完成,那么在这些操作完成之前,EndXXX方法都将等待  。
使用IAsyncResult.AsyncWaitHandle属性获取的WaitHandle调用WaitOne()方法,以便在操作完成之前,都进行等待  。然后调用EndXXX方法  。

  轮询IAsynResult.IsCompleted属性的返回值,以便确定异步操作何时完成  。然后调用EndXXX方法  。

  为提供给BeginXXX方法的回调函数(IasyncCallback类型)传递一个委托  。当异步操作完成时,将执行回调函数  。在回调函数的代码中调用EndXXX方法,从而获取结果  。

  示例2将说明使用WaitHandle获取执行异步查询的结果  。

  示例2:异步执行FOR XML查询

  <%@ Page Language="C#" ValidateRequest="false" %><%@ Import Namespace="System.Data" %><%@ Import Namespace="System.Data.SqlClient" %><%@ Import Namespace="System.Threading" %><%@ Import Namespace="System.Xml" %><%@ Import Namespace="System.Web.Configuration" %><%@ Import Namespace="System.Data.SqlTypes" %> http://www.w3.org/1999/xhtml">

注意,web.config文件中使用的连接字符串有一个新属性Asynchronous Processing,该属性设置为true:

  

  在示例2中,创建了SqlConnection和SqlCommand对象实例,接着将它们的属性设置为合适的值  。此后,调用SqlCommand对象的BeginExecuteXmlReader()方法,然后将该方法返回的IAsyncResult对象赋值给本地变量,便于随后使用:

  IAsyncResult asyncResult = command.BeginExecuteXmlReader();

  接下来,调用WaitHandle对象的WaitOne()方法,来等待查询执行结束  。注意,在调用WaitOne()方法之前,可自由实现一些其他处理  。

  // 此处实现一些其他处理 asyncResult.AsyncWaitHandle.WaitOne();

  注意,WaitOne()是一个锁定调用,这意味着直到查询结束之前,该方法都不会返回  。最后,通过调用EndExecuteXmlReader()方法(传递IasyncResult对象作为参数)来获取查询结果:
XmlReader reader = command.EndExecuteXmlReader(asyncResult);

  接着,将返回的XmlReader加载到XmlDocument对象中,然后显示输出:

  XmlDocument doc = new XmlDocument(); // 将XmlReader加载到XmlDocument对象中 doc.Load(reader); output.Text = "XML: "+ Server.HtmlEncode(doc.OuterXml);

  为了等待命令执行完成,示例2使用WaitHandle对象的WaitOne()方法  。WaitHandle类还包括其他静态方法,例如WaitAll()和WaitAny()  。这些静态方法将WaitHandle对象数组作为参数,同时根据调用的方法,当所有调用都完成时或者只要任一调用完成,立刻返回方法  。例如,如果调用三个独立的执行命令,每个命令都异步执行,同时在数组中为每个调用都设置WaitHandle,那么在这些命令都执行完成之前,将调用WaitAll方法  。这样可以让这三个命令在同一时间执行  。

  需要重点注意的是WaitOne(),WaitAll()和WaitAny()方法都可接受一个超时参数值  。使用这个超时设计,能够设置等待命令返回的时间数  。如果方法超时,则返回False值  。

  3、 SQL Server 2005中的XML数据类型

  SQL Server 2005的XML数据类型实现了ISO SQL-2003标准XML数据类型  。在XML数据类型列中,能够存储格式良好的XML 1.0文档以及包含文本节点的XML内容片段  。此外,还可以在非类型化XML列中存储任意数量的顶级元素  。在插入XML数据时,系统会检测格式良好的数据,同时拒绝非格式良好的数据  。服务器端验证的范围依靠XSD架构是否与XML数据类型列关联  。在查看XSD架构和XML列中的角色前,读者需要理解在XML数据类型列中存储原XML数据的原因  。在XML数据类型列中存储XML数据对于以下情况很适用:

  通过在SQL Server中存储XML数据,开发人员则具有了一种在服务器上存储XML数据的直接方法,这种方式可保护文档顺序和文档结构  。

  当需要查询和修改XML数据时  。
当需要与外界系统交换数据,而不用执行多种转换时  。
当所使用的XML文档结构复杂,或者XML文档复合不同的或者复杂的架构,而难于映射到关系型结构时  。

  3.1 类型化和非类型化XML列

  为更好的结构化或者验证XML数据,SQL Server可将架构与特定XML列关联起来  。这种列称为类型化XML列  。如果XML架构与XML列关联,那么在将XML数据插入字段时,架构会验证XML数据  。SQL Server 2005支持在架构集合中分组的多个架构,这样可以将不用的架构应用到XML列  。服务器将根据架构对输入XML进行验证  。如果XML对于集合的所有架构都有效,那么该XML数据将存储在XML字段中  。下表总结了类型化XML列和非类型化XML列的不同点  。

  除了类型化XML列,开发人员还可以针对类型化或者非类型化XML数据类型列使用关系型约束(列或者行)  。

  3.2 非类型化XML列

  当不需要优先使用架构时,非类型化XML则变得很有用,那么也就不需要使用基于映射的解决方案了  。当已经获取架构,但是映射的关系型数据模型非常复杂,难于维护,或者已经存在多个架构,同时没有绑定根据外部需要绑定数据时,非类型化XML也是很有用的  。以下语句在AdventureWorks数据库中创建了表Customer,该表主键是整数类型的ID列,同时具有一个非类型化XML列XmlData:

  Use AdventureWorks CREATE TABLE Customer(ID int primary key, XmlData xml)     在AdventureWorks数据库中创建的Customer表将在本文中使用  。为了在上表中插入值,可使用以下T-SQL语句:
INSERT INTO Customer values(2, Joe)

  注意,开发人员还可创建包括多个XML或者关系型列的表,该表可有主键,也可没有主键  。

  3.3 类型化XML列

  如果在XML架构集合中包括描述XML数据的XML架构,那么可以将该XML架构集合与XML列关联起来,以便生成类型化XML  。XML架构用于验证数据,在查询编译和数据修改过程中实现比非类型化XML更加精准的类型检测,以及优化存储和查询过程  。

  正如前文所述,使用SQL Server中的XML架构集合能够支持类型化XML列  。XML架构对象与其他SQL Server对象的定义类似,它们都存储在SQL Server中  。使用T-SQL语句CREATE XML SCHEMA COLLECTION,同时提供一个或者多个XML架构能够创建一个XML架构集合  。可以将多个XML架构组件添加到现有的XML架构中,同时使用ALTER XML SCHEMA COLLECTION语句还可以将多个架构添加到XML架构集合中  。使用SQL Server 2005的安全模型能够如同保护其他SQL对象那样保护XML架构集合  。T-SQL语句语法是DDL CREATE XML SCHEMA COLLECTION:

  CREATE XML SCHEMA COLLECTION AS -- 此处设置架构内容 GO
例如,为创建名为CustomerSchema的架构,可使用以下命令:
Create xml schema collection CustomerSchema as N

  除了使用XML架构集合实现类型化XML列之外,还可以将其用于类型化XML变量和参数  。

一旦创建CustomerSchema,那么就可以轻松的将其与Customer表的XmlData列关联起来,语法如下:

  CREATE TABLE Customer(ID int primary key, XmlData XML(CustomerSchema))

  当将值插入Customer表中,XmlData列中的XML数据将根据CustomerSchema进行验证:

  Insert into Customer values(1, http://www.wrox.com/books">Joe) GO Insert into Customer values(2, http://www.wrox.com/books">Fred)

  在将架构与XML列关联时,开发人员可以使用DOCUMENT或者CONTENT标志来设置是否能够在类型化列中存储XML树或者片段  。对于DOCUMENT而言,每个XML实例都会根据用来对其进行验证和类型化的命名控件,设置实例中顶级元素的目标命名空间  。另一方面,对于CONTENT而言,每个顶级元素都能够在架构集合中设置任一目标命名空间  。在生成实例过程中,将根据目标命名空间验证XML实例  。例如,开发人员可执行以下包括无效命名空间声明的SQL语句:

  Insert into Customer values(3, http://invalidnamespace/books">InvalidData) GO

  由于Insert语句中包括无效的命名空间,所以应该看到类似如下的错误消息:

  Msg 6913, Level 16, State 1, Line 1 XML Validation: Declaration not found for element http://invalidnamespace/books:customer. Location: /*:customer[1]

  3.4 将数据插入XML数据类型列

  无论XML列是类型化还是非类型化,开发人员都可采用以下方式为XML列提供值:(1)作为可隐式转换为XML数据类型的字符或者二进制SQL类型;(2)作为文件内容;(3)作为可生成XML数据类型实例的,包括TYPE指令的FOR XML语句输出  。

  提供的值必须经过格式良好的验证,这样才能存储XML文档和XML片段  。如果数据未通过格式良好验证,那么将显示适当的错误消息来拒绝  。对于类型化XML,检测提供的值是为了XML架构集合中XML架构测定XML列的一致性要求  。如果验证失败,则拒绝XML实例  。下面查看一下将值插入XML列中不同方法的示例:

  首先,以下语句将整数列ID的值2和XmlData列的实例作为新行插入Customer表中  。以字符串形式提供的实例会被隐式转换为XML数据类型,同时在插入过程中检测其是否格式良好:
INSERT INTO Customer values (2, http://www.wrox.com/books">Joe)

  正如前文提到的,对于Insert命令,还可能利用XML文件内容作为输入  。以下XML文档存储在名为Customer.xml文件中:

   Dave      如果执行以下T-SQL命令,将把Customer.xml文件内容加载到XmlData列中:
INSERT INTO Customer SELECT 7, xml_value FROM (SELECT * FROM OPENROWSET (BULK C:\Data\Customer.xml, SINGLE_BLOB) AS xml_value) AS R(xml_value)

  对于Insert命令而言,第三种方式是利用包括TYPE指令的FOR XML的输出作为输入  。在SQL Server 2005中,使用包括TYPE指令的FOR XML能够将结果生成为XML数据类型实例  。XML结果能够赋值给XML列,变量或者参数  。在以下语句中,使用FOR XML TYPE将生成的XML实例赋值给XML数据类型变量@var  。然后,在INSERT语句中使用该变量:
DECLARE @var xml SET @var = (SELECT XmlData FROM Customer FOR XML AUTO,TYPE) -- 将变量值插入新表CustomerOutput中 CREATE TABLE CustomerOutput (XmlData xml) INSERT INTO CustomerOutput (XmlData) VALUES (@var)

  3.5 XML数据类型方法

  虽然XML数据类型是内置数据类型,但是通过提供一些查询和更新存储在XML变量或者列中数据的方法,它的功能类似于用户定义数据类型(UDT)  。开发人员可使用这些方法查询,获取标量值,以及修改存储在变量,列或者参数中的XML文档  。下表列举了XML数据类型方法   。

  4、小结

  由于XML在计算机世界中是一种无孔不入的语言,所以SQL Server 2005和ADO.NET对XML提供功能丰富的内置支持是合乎逻辑的  。本文展示了SQL Server 2005的XML功能  。如果正确使用,那么这些XML功能可为整个架构带来有意义的变化  。

  

【责任编辑:碧海蓝天 TEL:(010)68476606】