更新和删除操作
虽然本文的重点是使用 SQL 搜索和检索存储在 XML 列中的数据,不过这里仍然值得花一点时间考虑一下另外两项常见的任务:更新和删除 XML 列中的数据。
DB2 允许用户使用 SQL 和SQL/XML 语句更新和删除 XML 数据。实际上,由于 XQuery 标准的初稿没有解决这些问题,DB2 用户必须依赖 SQL 来完成这些任务。
更新 XML 数据
DB2 允许用 SQL UPDATE 语句或通过使用系统提供的存储过程(DB2XMLFUNCTIONS.XMLUPDATE)来更新 XML 列。不管使用哪种方式,对 XML 列的更新都发生在元素级。然而,使用存储过程更新 XML 数据的程序员不需要提供整个 XML 文档给 DB2;他们只需指定要更新的 XML 元素。发出 UPDATE 语句的程序员则需要指定整个文档(而不仅仅是要更改的元素)。
例如,如果要发出一条 UPDATE 语句来更改某个特定客户的联系方式信息中的 email 地址,就必须在 XML 列中提供全部联系方式信息,而不仅仅是新的 email 元素值。根据 图 2,提供的信息将包括 "Address" 信息、"phone" 信息、"fax" 信息和 "email" 信息。
考虑以下语句:
清单 22. 示例 UPDATE 语句
update clients set contactinfo=( xmlparse(document '<email>newemail@someplace.com</email>' ) ) where id = 3227
回忆一下在 “DB2 Viper 快速入门” 中我们是如何插入 XML 数据的,这里的语句大部分仍然是类似的。与任何 SQL UPDATE 语句一样,这个例子首先标识出要更新的表和列。由于目标列包含 XML 数据,因此需要提供一个格式良好的 XML 文档作为新的目标值。虽然大多数生产环境在应用程序中使用主机变量或参数标记位来更新 XML 数据,但是在这里我展示了用一种简单的方式来交互式地完成该任务。第二行使用 XMLParse 函数将输入字符串转换成 XML。对于 beta 版的 Viper,需要显式地调用 XMLParse。当 Viper 变得普遍可用时,显式调用应该只是成为一种选择。最后一行是一个标准的 SQL 子句,规定只更新表中特定的一行。
如果执行上述 UPDATE 语句,则客户 3227 的 "contactinfo" 列将只包含 email 信息,如 清单 23 所示:
清单 23. 执行上述 UPDATE 语句的效果
<email>newemail@someplace.com</email>
这位客户的地址、电话号码和传真号码(如 图 2 所示)将丢失。而且,之前编写的用于提取客户的 email 地址的那些查询也无法恢复这些信息。为什么?之前的那些查询包括 XPath 或 XQuery 表达式,这些表达式在一个特定的文档层次结构中导航,而在这个结构中 Client 是根元素,email 是一个子元素。在像上面这样更新该文档之后,email 将变成这个客户的 XML 记录的根元素;因此,在这个层次结构中再也不能在预期的位置上找到它的值。
如果要交互式地更新这个客户的 email 地址,并且保留所有其他已有的联系方式信息,应该像 清单 24 中那样重写查询:
清单 24. 修改后的 UPDATE 语句
update clients set contactinfo=
(xmlparse(document
'‘<Client>
<Address>
<street>5401 Julio Ave.</street>
<city>San Jose</city>
<state>CA</state>
<zip>95116</zip>
</Address>
<phone>
<work>4084633000</work>
<home>4081111111</home>
<cell>4082222222</cell>
</phone>
<fax>4087776666</fax>
<email>newemail@someplace.com</email>
</Client>' ) )
where id = 3227
也许您想知道是否可以通过一个视图进行更新,从而避免提供整个 XML 文档。例如,清单 13 中定义的 commentview 使用 XMLTable 函数提取 XML 文档中的某些元素,并将这些元素转换成视图中的 SQL 列。那么,是否可以更新这些 SQL 列中某个列的值,并将结果写回到初始的 XML 文档的适当子元素中呢?答案是否定的。在 DB2 中,基于 SQL 类型的视图列与从一个函数(在这里是 XMLTable 函数)得到的视图列是有区别的。对后者的更新不受支持。
删除 XML 数据
删除包含 XML 列的行很简单。SQL DELETE 语句允许通过 WHERE 子句识别(或限制)要删除的行。该子句可以包括简单的谓词来标识非 XML 列值或包括 SQL/XML 函数来标识包含在 XML 列中的 XML 元素值。
例如,下面展示了如何删除客户 ID 为 3227 的客户的所有信息:
清单 25. 删除一个特定客户的数据
delete from clients where id = 3227
还记得怎样限制 SQL SELECT 语句,使之仅返回居住在邮政编码为 95116 的地区的客户的行吗?如果还记得的话,很容易知道如何删除与那些客户相关的行。下面看看如何使用 XMLExists 来做这件事:
清单 26. 删除居住在特定地区的客户的数据
delete from clients where xmlexists('$c/Client/Address[zip="95116"]' passing clients.contactinfo as "c");
建立索引
最后,值得注意的是,您可以创建专门的 XML 索引来加快对 XML 列中的数据的访问。由于本文是介绍性的文章,并且示例数据量比较少,所以本文不讨论这个话题。但是,在生产环境中,定义适当的索引对于取得非常好的性能是非常重要的。本文的 参考资料 小节可以帮助您了解更多关于新的 DB2 索引技术的知识。
结束语
本文谈到了很多基础知识,提到了 SQL/XML 的几个关键方面,并展示了如何使用 SQL/XML 查询 XML 列中的数据。当然,除了这里讨论的用法外,用 SQL 和 SQL/XML 函数还可以做更多的事。本文给出了一个 简单的 Java 例子,这个例子解释了如何使用参数标记位和 SQL/XML 来查询 XML 列中的数据。在将来的文章中我们将更详细地讨论应用程序开发。但是,接下来的文章将探索 DB2 Viper 支持的一种新的查询语言,即 XQuery 的一些有趣的方面。