纯 SQL 查询
即使您对 SQL 所知有限,也仍然可以很轻松地查询 XML 数据。例如,下面的查询选择 "clients" 表中的全部内容,包括存储在 "contactinfo" 列的 XML 信息:
清单 2. 简单的 SELECT 语句
select * from clients
当然也可以编写更具选择性的 SQL 查询,使之包含关系投影和限制操作。下面的查询检索所有具有 "Gold" 状态的客户的 ID、姓名和联系方式。请注意,"contactinfo" 列包含 XML 数据,而其他两列不包含 XML 数据:
清单 3. 带投影和限制的简单 SELECT 语句
select id, name, contactinfo from clients where status = 'Gold'
正如您所预料,您可以基于这样的查询创建视图,下面的 "goldview" 可以说明这一点:
清单 4. 创建包含 XML 列的视图
create view goldview as select id, name, contactinfo from clients where status = 'Gold'
不幸的是,很多事情光用 SQL 是无法解决的。通过纯 SQL 语句可以检索整个 XML 文档(刚才已证明这一点),但是却不能指定基于 XML 的查询谓词,也不能检索 XML 文档的某一部分或者 XML 文档中特定的元素值。换句话说,使用纯 SQL 不能对 XML 文档中的片段进行投影、限制、连接、聚集或排序操作。例如,您不能单独检索 Gold 客户的 email 地址或居住在邮政编码为 "95116" 的地区的客户的姓名。为了表达这些类型的查询,需要使用带 XML 扩展的 SQL(SQL/XML)、XQuery 或结合使用这两种查询语言。
下一节将探讨 SQL/XML 的几个基本特性。在接下来的文章中,我们将学习如何编写 XQuery 以及如何将 XQuery 与 SQL 结合使用。
SQL/XML 查询
顾名思义,SQL/XML 被设计用来为 SQL 和 XML 两者之间搭一座桥。它首先是 SQL 标准的一部分,经过演化现在包括将 XQuery 或 XPath 表达式嵌入 SQL 语句的规范。XPath 是用于导航 XML 文档以便发现元素或属性的一种语言。XQuery 包括对 XPath 的支持。
请务必注意,XQuery(和 XPath)表达式是大小写敏感的。例如,引用 XML 元素 "zip" 的 XQuery 并不适用于名为 "ZIP" 或 "Zip" 的 XML 元素。SQL 程序员有时候很难记住大小写敏感这一点,因为 SQL 查询语法允许使用 "zip"、"ZIP" 和 "Zip" 来引用同一个列名。
DB2 Viper 提供了超过 15 个 SQL/XML 函数,通过这些函数可以搜索 XML 文档中的特定数据,将传统数据转换成 XML,将 XML 数据转换成关系数据,以及执行其他有用的任务。本文不讨论 SQL/XML 的所有方面,而只是谈到几种常见的查询挑战,以及一些关键的 SQL/XML 函数如何解决这些挑战。
根据 XML 元素值 “限制” 结果
SQL 程序员常常编写根据某种条件限制从 DBMS 返回的行的查询。例如,清单 3 中的 SQL 查询限制从 "clients" 表中检索的行,使之只包括那些具有 "Gold" 状态的客户。在这个例子中,客户的状态可在 SQL VARCHAR 列中捕捉。但是,如果您想根据某种应用于 XML 列中数据的条件对搜索进行限制,那么应该怎么做呢?SQL/XML 的 XMLExists 函数为完成该任务提供了一种手段。
通过 XMLExists 可以在 XML 文档中找到一个元素,并测试它是否满足某个特定的条件。如果用在 WHERE 子句中,则 XMLExists 可以限制返回的结果,使之只包括那些包含具有特定 XML 元素值的 XML 文档的行(换句话说,指定的值等于 "true")。
让我们看看早先遇到的一个查询问题。假如您想找到居住在具有特定邮政编码的地区的所有客户的姓名。您也许还记得,"clients" 表的一个 XML 列中存储了客户的地址(包括邮政编码)。(见 图 2。)通过使用 XMLExists,可以从 XML 列中搜索目标邮政编码,并相应地限制返回的结果集。下面的 SQL/XML 查询返回居住在邮政编码为 95116 的地区的客户的姓名:
清单 5. 根据 XML 元素值限制结果
select name from clients where xmlexists('$c/Client/Address[zip="95116"]' passing clients.contactinfo as "c")
第一行是一个 SQL 子句,指定仅检索 "clients" 表 "name" 列中的信息。WHERE 子句调用 XMLExists 函数,指定一个 XPath 表达式,这个表达式使 DB2 找到 "zip" 元素并检查元素值是否为 95116。"$c/Client/Address" 子句表明 DB2 用于定位 "zip" 元素的 XML 文档层次结构中的路径。通过使用可以从节点 "$c"(稍后将会解释)访问的数据,DB2 将从 "Client" 元素中找到它的子元素 "Address",以便检查邮政编码("zip" 值)。最后一行决定 "$c" 的值:它是 "clients" 表的 "contactinfo" 列。因此,DB2 检查 "contactinfo" 列中的 XML 数据,从根元素 "Client" 深入到 "Address" 子元素再找到 "zip" 子元素,然后判断客户是否居住在目标地区。如果客户住在目标地区,则 XMLExists 函数的返回值为 "true",DB2 将返回与那一行相关的客户的姓名。
在使用 XMLExists 查询谓词时经常会出现一个错误,如 清单 6 所示。
清单 6. 根据 XML 元素值限制结果时采用的不正确语法
select name from clients where xmlexists('$c/Client/Address/zip="95116" ' passing clients.contactinfo as "c")
虽然这个查询也可以成功地执行,但是它不能限制结果,使之仅包含居住在邮政编码为 95116 的地区的客户。(这是由于标准中规定的语义造成的,而且这并不是 DB2 所特有的。)为了限制结果,使之仅包含居住在邮政编码为 95116 的地区的客户,需要使用前面 清单 5 中展示的语法。
您可能很想知道如何在应用程序中包括限制 XML 数据的查询。虽然本文不详细讨论应用开发话题,但还是提供了一个 简单的 Java 例子,这个例子在一条 SQL/XML 语句中使用一个参数标记位将输出限制为居住在给定地区的客户的信息。