DB2 中的 pureXML 支持为管理 XML 数据提供了高效且通用的功能。DB2 以 XML 数据自身固有的分层格式存储和处理这些数据,避免因为将 XML 存储为 CLOB 中的文本或将它映射为关系表而导致的性能和灵活性限制。与仅使用 XML 的数据库不同,DB2 V9 还提供了关系型数据与 XML 数据在数据库中的无缝集成 —— 甚至是表的某一行中的集成。这样的灵活性表现在语言支持中,使您可访问关系型数据、XML 数据,或者同时访问这两种数据。您可以通过以下四种可选方案中的任一种查询 XML:
关于使用 XQuery 和 SQL/XML 查询 XML 数据的介绍,请参阅 developerWorks 中的 前几期文章, “用 SQL 查询 DB2 XML 数据” 及 “使用 XQuery 查询 DB2 XML 数据”。本文假设您已经熟悉这两篇文章中介绍的基本概念。请注意,XPath 是 XQuery 的一种子语言,因此我们提到 XQuery 时,也暗中包含 XPath 语言。如果您使用过 DB2 XML Extender 中的 XSLT 样式表或位置路径,那么您应该已经了解 XPath。在很多时候,使用 XPath 足以提取 XML 值或表示 XML 谓词,因此,即便您还不熟悉 XQuery 的所有其他特性,也可以开始使用 XPath。
DB2 使您能够利用所有这些可选方案最大限度地提高生产力、使查询适应应用程序的需求。本文将说明的问题如下:
让我们先给出一个高度总结,然后再详细研究各个可选方案的细节和特定实例。
您 可以在普通 XQuery、SQL/XML 或具有内置 SQL 的 XQuery 中表达许多查询。在特定情况下,您可能会发现其中之一能够比其他方案更为直观地表达您的查询逻辑。一般而言,查询 XML 的 “正确” 途径需要在 “逐个处理” 的基础上加以选择,需要考虑应用程序的具体需求和特征。但我们可总结出以下指导原则。
无论您选择在一条语句中怎样结合 SQL 和 XQuery,DB2 都使用一种混合编译器来为整个查询生成及优化一种执行规划 —— 不会导致查询执行的性能损失。
下表总结了查询 XML 数据的四种不同可选方案的各自优点。
| 普通 SQL | SQL/XML | 普通 XQuery | 嵌入了 SQL/XML 的 XQuery | |
|---|---|---|---|---|
| XML 谓词 | - | ++ | ++ | ++ |
| 关系谓词 | ++ | ++ | - | + |
| XML 及关系谓词 | - | ++ | - | ++ |
| 将 XML 与关系型相连接 | - | ++ | - | ++ |
| 将 XML 与 XML 相连接 | - | + | ++ | ++ |
| 转换 XML 数据 | - | o | ++ | ++ |
| 插入、更新和删除 | ++ | ++ | - | - |
| 参数标记 | + | ++ | - | - |
| 全文本搜索 | + | ++ | - | ++ |
| XML 聚集与分组 | - | ++ | o | o |
| 函数调用 | ++ | ++ | - | ++ |
在上表中,“-” 表示给定语言不支持某项特性;“+” 表示支持此特性,但存在更有效或更便捷的方式;“++” 表示给定语言极为适合表现该特性;最后,“o” 表示尽管可表现此特性,但从某种程度上来说,效果非常糟糕或者效率很低。
现在,让我们来定义一些示例数据和表,以查看具体的查询示例。
在 讨论 XML 查询可选方案的过程中,我们使用了以下三个表。dept 表有两列,列名分别为 unitID 和 deptdoc。dept 表的每一个行都描述了一家虚构企业的一个部门。unitID 列标识包含部门的单位(一个单位可能包含多个部门),deptdoc 列包含一个列出部门中的员工的 XML 文档。project 表只有一列,列名为 projectDoc,类型为 XML。projectDoc 表中的每一个行都包含一个描述特定项目的 XML 文档。一个项目可能会涉及到多个部门。为阐明混合关系型查询、XML 查询和连接,我们还提供了一个纯粹的关系型表 —— unit,其中列出了各单位的名称、主管等信息。一个单位可包含多个部门。
create table dept( unitID char(8), deptdoc xml) |
| unitID | deptdoc | |
|---|---|---|
| WWPR |
| |
| WWPR |
| |
| S-USE | ... | |
| ... | ... |
create table project(projectDoc xml) |
| projectDOC | |
|---|---|
| |
|
create table unit( unitID char(8) primary key not null, name char(20), manager char(20),…) |
| unitID | 名称 | 主管 | ... |
|---|---|---|---|
| WWPR | Worldwide Marketing | Jim Qu | ... |
| S-USE | Sales US East Coast | Tom Jones | ... |
| ... | ... | ... | ... |
您 可使用不带任何 XPath 或 XQuery 的普通 SQL,在不使用 XML 谓词的情况下读取整个文档。只要应用程序能识别出 XML 文档,从而基于同一表中的关系谓词进行全文档检索,那么这种方法就是一种非常简单易行的方法。例如,查询 1 检索 “WWPR” 这个单位的所有 department 文档:
|
同样,查询 2 返回 Jim Qu 所管理的所有部门的 XML 数据。
|
显而易见的缺陷就是您无法表示关于 XML 数据本身的谓词,也无法仅检索 XML 文档的片段。在我们的示例中,普通 SQL 不足以实现仅选择部门 PR27 且仅返回员工姓名这项任务。
若您的查询不需要在 XML 上应用谓词,并且总是返回整个 XML 文档,那么普通 SQL 足以满足您的需要。在本例中,将在 VARCHAR 或 CLOB 列中存储 XML,对于全文档插入及检索操作而言,这将给您带来一定的性能优势。
普通 SQL 没有使用 DB2 V9 支持的任何 SQL/XML 或 XQuery,但它依然允许在查询中使用全文本搜索条件。通过 DB2 Net Search Extender, 您可以在 XML 列上创建全文本索引来支持文本搜索 —— 从基本的关键字搜索到高级的 37 种语言的词干提取(stemming)、辞典(thesaurus)和模糊搜索。您还可以通过 path 表达式将文本搜索限定为仅搜索特定文档部分。以文本-索引查找为基础,查询 3 返回 /dept/description 目录下所有包含字符串 “sales” 的 department 文档:
|
SQL/XML(嵌入 SQL 中的 XQuery/XPath)
SQL/XML 是 SQL 语言标准的一部分,定义了一种新的 XML 数据类型以及多种查询、构造、验证和转换 XML 数据的函数。DB2 V8 已加入了许多 SQL/XML 发布函数,使用户能够使用 XMLELEMENT、XMLATTRIBUTE、XMLFOREST、XMLAGG 和其他一些函数将关系型数据构造为 XML。
DB2 9 添加了新的 SQL/XML 查询函数,包括 XMLQUERY、XMLTABLE 函数以及 XMLEXISTS 谓词。这些函数允许用户在 SQL 语句中嵌入 XQuery 或简单的 XPath 表达式。
如查询 4 所示,XMLQUERY 函数通常用在 select 子句中,用于从 XML 列中提取 XML 片段,而 XMLEXISTS 通常在 where 子句中使用,用于在 XML 数据上应用谓词。
|
这个示例查询使用 XMLEXISTS 来选择 “WW” 部门 V15,并应用 XMLQUERY 来返回该 department 文档中的所有员工姓名。查询结果如下:
| WWPR | Matt Foreman |
此查询还突出展示了以一种整合的方式使用 SQL/XML 查询 XML 数据和关系型数据的方法。select 子句从关系型列和 XML 列中检索数据,而 where 子句包含关系型谓词和 XML 谓词。我们可使用 XMLTABLE 函数表示同一查询,如查询 5 所示。在这种格式的查询中,我们指定了条件,以限制输入数据并提取那些我们感兴趣的输出值。在查询 5 中,XMLTABLE 函数中的 XQuery 表达式指定了在部门 V15 中工作的员工,而 COLUMNS 子句中的 path 表达式(“name/text()”)则返回其名称。此查询的输出结果与查询 4 相同。
|
SQL/XML 方案具有以下优点:
|
|
为完成此连接,我们将 unit manger 传递到 XMLEXISTS 谓词之中,这样实际连接条件就是一个 XQuery 谓词。反之,我们可将 XML 文档中的员工姓名提取出来,传递到 SQL 上下文中,从而使连接条件成为一个 SQL 谓词:
|
通 常,查询 7 要优于查询 8,因为 XMLCAST 函数只需要一个输入值。但在我们的示例中,对于那些有着多名符合条件的员工的部门,此查询将失败。查询 8 使用了 XMLCAST,对于各文档只需进行一次 XML 值连接非常有用,因为它允许在 unit.manager 上使用关系型索引。此索引无法在查询 7 中使用,因为其连接条件并非关系型谓词,而是一个 XQuery 谓词。
|
|
在 查询 10 中,XMLTABLE 函数从带有 “emp” 和 “office” 这两列的表形式的所有文档中提取 /dept/employee/name 和 /dept/employee/office。对该表使用 SQL 的 group by 函数和聚集函数通常比使用生成相同结果的普通 XQuery 更有效。
请注意,在查询 10 中多获得了一行,这是因为 SQL 的 group by 函数还为 NULL 值生成一个组,我们的示例表中有一名员工没有办公室信息。查询 9 没有为该员工生成一行,因为 for 循环遍历的是不同的 office 值,这些值不包括丢失的办公室信息。
|
在查询 11 中,我们将每一个 dept 和 project 文档放入 XMLEXISTS 中传递给 XQuery,并在那里表示连接条件。您可能会发现,在普通 XQuery 中(查询 13)编写此类连接更为简单高效。
让 我们暂时回过头来,问一个问题:什么是 XQuery,我们又为什么需要使用 XQuery?正如 SQL 是为关系型数据模型设计的查询语言一样,XQuery 是专为查询 XML 数据设计的语言。由于 XML 数据可能与关系型数据有很大的差异,因此我们需要一种专门的语言来高效处理 XML 数据。关系型数据是平面的、高度结构化、强类型化、无序的,而 XML 数据是有序、嵌套的、层次化的、可选类型化的,并且往往不规则且是不完全结构化的。SQL 无法处理这样的情况,但 XQuery 专门为此设计。具体而言,XQuery 设计用于遍历 XML 文档树,并提取 XML 片段,而且还包括一些表达式,这些表达式用于创建、操纵和遍历 XML 项序列及构建新的 XML 数据。
IBM 已扩展了 DB2 的所有主要应用程序编程接口(API),以支持将 XQuery 作为 SQL 那样的一流语言。其中包括 CLI/ODBC、嵌入式 SQL、JDBC 和 .NET。因此,DB2 命令行处理器也支持 XQuery。您可按原样提交 XQuery,但需要使用 XQUERY 关键字启动它们,以通知 DB2 使用 XQuery 解析器,如下例所示:
|
查询 12 遍历各 department 文档中的 “dept” 元素,并返回在部门 PR27 工作的员工姓名。
|
在查询 6 中,可以看到 SQL/XML 允许您将一个 SQL 参数标记作为变量传递到嵌入式 XQuery 表达式中。SQL/XML 查询的 select 子句中通常有一个 XMLQUERY 函数,用于提取 XML 文档的某些部分;where 子句中通常会有一个 XMLEXISTS 谓词,用于过滤满足条件的文档。如果您希望在一条 FLWOR 表达式中表示整个查询逻辑,而不是使用两个单独的 XQuery 调用(XMLQUERY 中的一个调用和 XMLEXISTS 中的一个调用),并且希望依然使用参数标记,那么可以考虑将查询 12 重写为查询 14 所示形式:
|
查 询 14 是一个 SQL/XML 语句,因为它是 SQL fullselect 的 values 子句。values 子句通过指定结果表中的各列表达式来返回一个值表。在查询 14 中,结果表为 XML 类型的单行单列表,XMLQUERY 函数生成输出列的值。所有员工名都将在一个 XML 值中返回给客户机。查询 14 中的 FLOWR 表达式几乎与查询 12 中的表达式相同,惟一的不同在于查询 14 包含一个外部变量($z),此变量被作为参数传递到 XMLQUERY 函数中。
普 通 XQuery 允许且只允许访问 XML 数据。如果只处理 XML 数据,那么这种方案非常好,但如果应用程序需要利用两种语言和数据模型的全部力量,综合访问 XML 数据和关系型数据,那么普通 XQuery 不足以胜任。使用本文前面讨论过的 SQL/XML —— 嵌入了 XQuery 的 SQL —— 可完成此任务。相反地,嵌入了 SQL 的 XQuery 为您带来了额外的可能性。除前文列出的优缺点之外,还有以下几个重要的方面:
|
两个表的 unitID 列上的常规关系索引以及 unit 表的 manager 列上的常规关系索引有助于提高嵌入式 SQL 查询的速度。
|
|
|
|
|
查询 20 的输出结果形式如下所示:
|
您 需要注意的一件事就是:根据编写具体查询的方式不同,DB2 可能会交付不同格式的查询结果。例如,普通 XQuery 返回结果集形式的项(例如元素或文档片段),一项作为一行,即便多个项来自数据库中的同一文档(行)也是如此。另一方面,在使用 XMLQUERY 函数时,SQL/XML 可能会在一行中返回多个项,而不是返回多个独立的行。在某些情况下,您会认为这很令人满意,但在某些情况下又并非如此,具体取决于您的特定应用程序。让我 们来看看示例。
查询 21 和查询 22 均请求获得 dept 文档中的员工姓名。查询 21 以 SQL/XML 方式表示,而查询 22 是用 XQuery 编写的。
|
|
查询 21 为每个 dept 文档都返回一行,每个行都包含在该部门中工作的员工姓名:
而查询 22 将每一个员工姓名作为独立的一行返回:
查 询 22 的结果通常更易于为应用程序所用,即:一次处理一个 XML 值。但在这个示例中,您并不知道哪些 name 元素来自同一个 department 文档。查询 21 的输出结果保留了这一信息,但应用程序利用其结果较为困难,因为应用程序可能需要分离这些结果行,以便分别访问每个 name 元素。如果应用程序使用 XML 解析器从 DB2 中获取每个 XML 结果行,那么解析器将拒绝查询 21 的第一个结果行,因为它并非格式良好的文档(缺少单独的根元素)。为解决此问题,您可向查询 21 中添加一个 XMLELEMENT 构造函数,从而添加一个根元素,如查询 23 所示:
|
查询结果发生了改变,每个结果行都是一个格式良好的 XML 文档:
| .... |
回 忆一下,查询 14 使用了一个 SQL values 子句和 XMLQUERY 函数来允许向 XQuery 传递参数。但查询 14 的输出结果为单行,其中包含所有员工的姓名。如果您更希望使各员工的姓名自成一行,同时还需要使用参数标记,那么可以借助 XMLTABLE 函数,如查询 24 所示:
|
DB2 V9 为查询 XML 数据提供了一组丰富的选项。您将根据应用程序的需求和特征选择最适合您的方案。如果需要结合关系型数据和 XML 数据,那么 SQL/XML 在绝大多数情况下都是最佳选择。具体而言,SQL/XML 方案允许您为 XML 数据使用参数标记。如果仅涉及 XML 的应用程序,那么独立 XQuery 是一种功能强大的方案,嵌入式 SQL 可进一步增强它,支持您使用全文本搜索和 UDF 调用。本文所讨论的示例帮助您作出了明智的决策。您可使用我们的查询模式作为起点,编写自己的查询,查询您自己的 XML 数据。
一 个通用的指导原则就是根据实际需要为查询引入恰如其分的复杂性。例如,使用一个带有内置 XQuery 的嵌入式 SQL 语句的 XQuery 是完全可能的。但是,我们的经验显示,表达所需的查询逻辑通常并不需要两种语言的嵌套层次超过一层。因此,我们建议仅在 SQL 中使用一层嵌入式 XQuery,反之亦然。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/15082138/viewspace-623543/ ,如需转载,请注明出处,否则将追究法律责任。