DB2 SQL 与 XQuery 教程,第 7 部分: XML 与 XQuery 简介
2009-11-28 00:00:00 来源:WEB开发网开始之前
关于本系列
本系列教程为您讲解 SQL 的一些基础和高级话题以及 XQuery 的基础知识,并展示如何使用 SQL 查询或 XQuery 语句将常被问起的业务问题表达为数据库查询。开发人员和数据库管理员可以使用本教程来提高他们的数据库查询技能。Academic Initiative 成员可以使用本教程系列作为他们数据库课程的一部分。
本文中的所有例子都是基于 Aroma,这是一个示例数据库,其中包含了在美国各地的商店中出售的咖啡和茶用品的销售数据。每个例子由以下三部分组成:
以日常用语表达的一个业务问题
以 SQL 或 XQuery 表达的一个或多个例子查询
显示从数据库返回的结果的一个表
本指南是为了让读者学习 SQL 语言和 XQuery 而设计的。和学习任何其他技能一样,重要的是一边学习一边实践。本指南给出的表定义和数据为学习提供了便利。
对于使用本指南作为学校课程一部分的学生而言,他们应该向老师学习连接到 Aroma 数据库的操作,并了解本指南的设置与您本地设置的不同之处。
本教程是针对 DB2 Express-C 9 for Linux®, UNIX®, and Windows® (曾用名 Viper)编写的。
关于本教程
本教程向读者介绍 pureXML 和 XQuery。在 Aroma 数据库中,惟一用到 XML 的地方就是 Comments 列。本系列的 第 1 部分中提到过这一列,这正是本教程,即本系列的第 7 部分的重点所在。
本教程首先对 XML 数据类型的特征和优点做一个基本的概述,然后将它与标准关系表进行比较。随后,要求用户编写检索 XML 元素的 XQuery 查询,根据 XML 值过滤数据,转换 XML 输出,并使用各种子句更精确地选择数据。本教程的最后一节介绍如何混合使用 XQuery 与 SQL,将这两种语言的威力组合起来。
连接到数据库
在使用 SQL 查询或操纵数据之前,需要连接到一个数据库。CONNECT 语句将一个数据库连接与一个用户名相关联。
如果您使用本指南作为学校课程的一部分,那么可以向老师询问要连接到的数据库的名称。对于本系列,数据库名为 aromadb。
要连接到 aromadb 数据库,可以在 DB2 命令行处理器中输入以下命令:
CONNECT TO aromadb USER userid USING password
注意用老师告诉您的用户 ID 和密码替换 "userid" 和 "password"。如果不需要用户 ID 和密码,那么只需使用以下命令:
CONNECT TO aromadb
如果看到下面的消息,则说明您已经建立一个成功的连接:
Database Connection Information
Database server = DB2/NT 9.0.0
SQL authorization ID = USERID
Local database alias = AROMADB
建立连接后,就可以开始使用数据库了。
关于 XML
什么是 XML?
XML:
是不同的系统、平台、应用程序和组织之间交换数据的标准。
独立于供应商和平台。
高度灵活。
适用于结构化、非结构化和半结构化数据的任意组合。
易于扩展 —— 可以随需定义新的标记。
容易转换为 “不同外观” 的 XML,甚至可以转换成其他格式,例如 HTML。
容易检查是否遵从某种模式。
通过大量可用的工具和标准,例如 XML 解析器、XSLT 和 XML 模式,以上几点都已成为可能。它们大大减轻了应用程序处理专用数据格式的负担。在消息格式、业务形式和服务频繁变化的时代,XML 减少了为此需要对应用程序逻辑作出相应维护的成本和时间。
除了将 XML 用于数据交换以外,企业还以 XML 格式永久保存大量业务关键数据。原因很多,主要包括:
出于审计和法规顺从性的目的,有些业务必须以原始格式保留 XML 文档,
例如法律和财政文档,在政府部门这一点尤为突出。
与关系模式相比,XML 是更适合的数据模型。不但对于面向内容的应用程序是这样,对于某些面向数据的应用程序也是如此,
例如,在生命科学应用中,数据高度复杂,且具有分层的性质,可能包含相当多非结构化信息。目前,大多数基因组数据仍然以专用的平面文件格式存放,但是大家正在努力将其转移到 XML 格式。
关系数据库已经在提供对 XML 数据的存储、处理、搜索和检索功能。这通常是基于将 XML 文档存储到 LOB 中,或者将 XML 映射和分解成关系模式。
这些解决方案在功能上和性能上都有其固有的局限性。通常,基于 LOB 的存储便于较快地插入和检索整个文档,但是由于在查询执行时需要进行 XML 解析,在搜索和提取信息方面的性能不佳。如果在插入时建立索引,一定程度上可以提高这方面的性能。这样做虽然可以加快查找符合搜索条件文档的查询的速度,但是会增加 XML 解析方面的开销。而且,文档片段的提取和子文档级的更新仍然需要代价不菲的 XML 解析。
在本教程系列之前的几个部分中,您已经阅读了关于 SQL 的一些介绍,包括 SELECT 语句和数据定义语言(Data Definition Language,DDL)。XML 是另一种不同的组织数据和查询数据的方式,它使用 XQuery 或 Xpath 来查询数据。
在表格式中,关系数据被表示为行和列上的数据。XML 数据则将标记和数据放在一起。
示例数据
<Comments>
<comment>
<comment_ID>5301</comment_ID>
<customer_info>
<fname>Scott</fname>
<lname>Phillips</lname>
<email>Scott_Phillips@hotmail.com</email>
</customer_info>
<feedback>
<type>opinion</type>
<content>Gold Tips was highly enjoyable!</content>
</feedback>
<store_rating>
<score>5</score>
<out_of>5</out_of>
</store_rating>
<store_response>
<required>no</required>
</store_response>
</comment>
<comment>
<comment_ID>5302</comment_ID>
<customer_info>
<fname>Barbara</fname>
<lname>Adams</lname>
<phone>6138617611</phone>
</customer_info>
<feedback>
<type>question</type>
<content>What are the top teas brands?</content>
</feedback>
<store_rating>
<score>4</score>
<out_of>5</out_of>
</store_rating>
<store_response>
<required>yes</required>
<completed>yes</completed>
<action>Please see our "All About Tea" page at www.aroma.com/tea</action>
|-------10--------20--------30--------40--------50--------60--------70--------80--------9|
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
</store_response>
</comment>
</Comments>
单凭以上示例数据,是否能确定 Scott Phillips 的电子邮箱地址?其实只需顺着嵌套标记创建的层次就能找到。由于 XML 将标记和数据存储在一起,因此数据是自描述的,容易理解。
DB2 9
DB2 9 是业界第一款能同时管理关系结构和 pureXML 结构的数据的混合型数据服务器。长期以来,DB2 一直提供高性能的数据存储和基于 SQL 标准的对关系数据的访问方式,同时提供的还有诸如数据分区和高级索引之类的数据存储优化和查询优化技术。现在,DB2 在它已有的关系引擎的基础上,更是引入了一种用于 XML 数据的优化的数据存储引擎。
应用程序开发人员如今可以将 XML 数据直接存储在 DB2 服务器中,并立即获得事务处理、高级数据弹性(resiliency)、安全访问等方面的优点,当然还有使用 XQuery 搜索大量 XML 数据的能力。
XML 数据与关系数据的比较
XML 有三大基本特性使之区别于关系模型:
XML 是自描述的。文档不仅包含数据,还包含必要的元数据。因此,不需要模式的静态定义,便可以搜索或更新 XML 文档。而关系模型则需要更多的静态模式定义。一个表中的所有行都必须有相同的模式。
XML 是分层的。文档不仅表示基本信息,还以分层的形式表示关于数据项之间关系的信息。而在关系模型中,所有关系信息都需要通过主键或外键关系来表达,或者在其他关系中表示。
XML 是面向序列的(排序很重要)。关系模型则是面向集合的;排序并不重要。
以上三点中,任何一点都不能表明 XML 比纯关系模型好或者坏。实际上,XML 和关系模型是互补的解决方案。有些数据具有分层的性质,有些数据具有标量的性质;有些数据有更严格的模式,而有些数据的模式不是那么严格;有些数据需要符合特定的顺序,有些数据则不需要。
何时使用 XML
在以下情况下,使用 XML 表示法较好:
模式是易变的。
如果数据的模式经常变化,考虑到变更关系模式的代价和难度,使用关系的形式表示这种数据不划算。而 XML 的自描述性可以使得模式的修改更为简单。
数据具有分层的性质。
有些数据具有标量的性质,对于这种数据,关系模型最为适合。但是还有一些数据具有分层的性质,而 XML 通常最适合表示这种数据。
数据表示业务对象,且一旦离开业务对象的上下文,其各个组成部分就失去意义。
例如,考虑一种典型的雇员和电话号码之间的关系,其中一个雇员可以有多个电话号码:一个是办公室电话号码,一个是传真号码,一个是家里电话号码,还有一个是手机号码。如果最常见的用法是根据雇员检索电话号码,那么,将数据标准化,引入一个表来跟踪与一名雇员相关联的多个电话号码,这种做法不是很合理。更好的选择是将电话号码放在雇员关系中,使用 XML 表示它们。
应用程序具有稀疏属性。
有些应用程序有很多可能出现的属性,但是对于任意给定的数据值,其中大部分属性都是缺少的。一个典型的例子就是商品编目。用于跟踪给定商品的不同属性的数目繁多,包括大小、颜色、织物、电源要求等等。但是,对于任何给定的对象,只有一部分属性是相关的;我们可以说一件毛衣的织物是什么,但是提起割草机的织物就荒谬之极。使用关系表来描述对象的特征成本很高,而且过于复杂。而将描述性的属性表示为 XML 数据则是更自然的表示法,而且可以减少复杂性和搜索成本。
少量数据是高度结构化的。
在很多应用程序中,结构化信息对于应用程序至关重要,但是其数量很少。虽然可以用常规的关系来表示那样的信息,但是这种方法会导致大量关系模式。相反,使用一个 XML 列,再辅以多种视图,可以大大减少数据库中受管理的对象的数量,从而减少维护成本。
创建支持 XML 的数据库
在本系列的 第 1 部分中,介绍了用一个批处理文件创建 Aroma 数据库。您可能想在将来创建自己的数据库,所以本节将教您如何创建支持 XML 特性的数据库。
用 Control Center 创建数据库
在 DB2 Control Center 中,在左侧菜单中右键单击 All Databases 文件夹。选择 Create Databse -> Standard。这时将弹出 Create Database Wizard。填入数据库的名称,然后选择 Enable database for XML。
XML 编码集
连续两次单击 Next,进入 Region 屏幕。将 Country/Region 值设为适当的值,将 Code set 设为 UTF-8。单击 Finish 完成数据库的创建。
用 Command Line Processor 创建数据库
要用 DB2 CLP 创建相同的数据库,可输入以下代码:
db2 create db aromadb using codeset utf-8 territory us
注意指定 UTF-8 作为数据库的编码集。XML 特性只能用于以编码集 UTF-8 定义的只有一个数据库分区的数据库。将来您在创建自己的数据库时别忘了包括这个参数。
关于 comments 列
在 Aroma 数据库中,Sales 表有一个 Comments 列。
这个列由以下信息组成:
评论 ID
客户信息:姓名、联系方式(电话号码和/或电子邮箱地址)
商店的响应(如果有的话)
客户反馈:可以是意见、建议或疑问
最高为 5 分的商店评分
示例数据
<Comments>
<comment>
<comment_ID>5301</comment_ID>
<customer_info>
<fname>Scott</fname>
<lname>Phillips</lname>
<email>Scott_Phillips@hotmail.com</email>
</customer_info>
<feedback>
<type>opinion</type>
<content>Gold Tips was highly enjoyable!</content>
</feedback>
<store_rating>
<score>5</score>
<out_of>5</out_of>
</store_rating>
<store_response>
<required>no</required>
</store_response>
</comment>
<comment>
<comment_ID>5302</comment_ID>
<customer_info>
<fname>Barbara</fname>
<lname>Adams</lname>
<phone>6138617611</phone>
</customer_info>
<feedback>
<type>question</type>
<content>What are the top teas brands?</content>
</feedback>
<store_rating>
<score>4</score>
<out_of>5</out_of>
</store_rating>
<store_response>
<required>yes</required>
<completed>yes</completed>
<action>Please see our "All About Tea" page at www.aroma.com/tea</action>
</store_response>
</comment>
</Comments>
为什么用 XML?
前面几个小节已经讨论过 XML 的优点,但是在这个例子中,为什么选择 XML 列,而不是关系表列呢?
灵活性:
- 商店希望得到客户的不同信息。
- 随着时间的推移,商店可能改进其获取反馈的方法,从而导致不同类型的数据出现。
- 例如,促销调查不同于常规的销售调查。这种变化用 XML 比较容易存储,但是用关系列就不行。
敏捷性:
- 表结构不需要随数据变化。
自描述性:
- 商店经理/雇员可以直接理解 XML 形式的客户评论,而不需要额外的解释。
层次性:
- 数据具有分层的性质。
- 如果离开评论的上下文,客户信息就变得没有意义。
问题示例
Aroma 数据库中存储了哪些评论?
纽约的商店收到了哪些评论?
哪些评论需要商店作出响应?哪些评论还没有处理完?
以 HTML 列表的形式显示所有未处理完的评论。
显示所有评论,并按照三种类别(评论、建议和疑问)对它们进行分组。
计算和显示每种类型的评论的数量。
计算和显示所有评论给出的平均评分。
使用中的注意事项
在 Sales 数据库中,comments 列只有从 2006 年 3 月开始的那些行的值。
关于 XQuery
在之前的例子中,都是使用 SQL SELECT 语句提取数据。涉及 XML 数据的查询可以用 XML 自己的查询语言,即 XQuery 来完成。
XQuery 在一些关键方面与 SQL 有所不同,主要是因为这两种语言是为具有不同特征的不同数据模型而设计的。XML 文档包含层次,并且有固有的顺序。而基于 SQL 的 DBMS 所支持的标量数据结构是平面的,又是基于集合的。行之间没有顺序。
这两种数据模型之间的差异,导致它们相应的查询语言在很多基本方面存在差异。下面的表列出了一些差异。
XQuery | SQL |
支持路径表达式,使程序员可以在 XML 的层次结构中导航 | 不支持路径表达式 |
支持有类型的和无类型的数据 | 总是用特定类型进行定义 |
不存在 null 值,因为 XML 文档忽略没有的或未知的数据 | 使用 null 值表示没有的或未知的数据值 |
返回 XML 数据序列 | 返回不同 SQL 数据类型的结果集 |
两种类型的 XQuery 表达式
本教程主要讨论两种重要类型的 XQuery 表达式:“FLWOR” 表达式和路径表达式。
FLWOR 表达式很像 SQL 中的 SELECT-FROM-WHERE 表达式 —— 它用于在一组项目中进行迭代,可选地返回从每个项目计算到的值。而路径表达式则是在 XML 元素的层次结构中进行导航,并返回路径末端找到的元素。
和 SQL 中的 SELECT-FROM-WHERE 表达式一样,XQuery FLWOR 表达式可能包含一些以某个关键词开头的子句。下面的关键词用于开始 FLWOR 表达式中的一个子句:
1. for | 迭代一个输入序列,将一个变量依次绑定到每个输入项 |
2. let | 声明一个变量并为之赋值,可能是包含多个项的一个列表 |
3. where | 指定用于过滤查询结果的标准 |
4. order by | 指定结果的排序顺序 |
5. return | 定义要返回的结果 |
XQuery 中的路径表达式由一系列的“步”组成,之间以斜杠相隔。简言之,每一步在 XML 层次中往里导航一层,以发现前一步返回的元素的子元素。路径表达式中的每一步可能还包含一个谓词,用于过滤那一步返回的元素,只保留满足某种条件的元素。
例如,对于前一小节给出的示例数据,假设变量 $comments 被绑定到一系列包含 <comment> 元素的文档,那么四步路径表达式 $comments/comment/feedback[type = "suggestion"]/content 将返回属于类型 "suggestion" 的评论的内容的列表。
在很多情况下,可以使用 FLWOR 表达式或路径表达式编写查询。
检索 XML 元素
问题
Aroma 数据库中存储了哪些客户评论?
例子 FLWOR 查询
xquery
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')
return $y
例子路径查询
xquery
db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')
两个查询,一个结果
<Comments>
<comment>
<comment_ID>1</comment_ID>
<customer_info>
<fname>Christopher</fname>
<lname>Davis</lname>
<phone>4147301265</phone>
<email>Christopher.D@hotmail.com</email>
</customer_info>
<feedback>
<type>opinion</type>
<content>The employee named Heather Gray was very helpful.</content>
</feedback>
<store_rating>
<score>5</score>
<out_of>5</out_of>
</store_rating>
<store_response>
<required>no</required>
</store_response>
</comment>
</Comments>
<Comments>
<comment>
<comment_ID>101</comment_ID>
<customer_info>
<fname>Cynthia</fname>
<lname>Thomas</lname>
<email>CThomas@hotmail.com</email>
</customer_info>
<feedback>
<type>question</type>
<content>What countries are major tea consumers?</content>
</feedback>
<store_rating>
<score>4</score>
<out_of>5</out_of>
</store_rating>
<store_response>
<required>yes</required>
<completed>yes</completed>
<action>Please see our "All About Tea" page at www.aroma.com/tea</action>
</store_response>
</comment>
</Comments>
...
注意:为了便于阅读,结果在格式上有所调整。实际上,DB2 Command Editor 每行显示一条评论。
提示:为了为 Command Editor 释放内存,在结果区域单击右键,然后选择 Clear Results。 |
关于这两个查询
为了在 DB2 9 中直接执行 XQuery 查询,必须在查询的开头加上关键词 xquery。这个关键词指示 DB2 调用它的 XQuery 解析器来处理请求。
注意:只有在使用 XQuery 作为最外层(顶层)语言时,才需要这么做。如果是将 XQuery 表达式嵌入到 SQL 中,那么不需要在表达式的前面加上 xquery 关键词。
当使用 XQuery 作为顶层语言时,XQuery 需要一个输入数据的来源。XQuery 获得输入数据的一种方法是调用一个名为 db2-fn:xmlcolumn 的数据源,调用该函数时带一个参数,标识一个 DB2 表的表名和其中一个列的列名。
db2-fn:xmlcolumn 函数返回存储在给定列中的一系列的 XML 文档。这两个例子查询返回一系列的包含客户评论信息的 XML 文档。
注意,列名 Comments 和表名 aroma.sales 都是以大写形式指定的。这是因为它们在被写入到 DB2 的内部编目之前,通常会被转换成大写形式。因为 XQuery 是大小写敏感的,小写的表名和列名与 DB2 编目中大写的名称不能匹配。
检索特定的 XML 元素
问题
Aroma 数据库中存储了哪些客户评论?只显示评论的内容。
例子 FLWOR 查询
xquery
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback/content
return $y
例子路径查询
xquery
db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback/content
两个查询,一个结果
<content>The employee named Heather Gray was very helpful.</content>
<content>What countries are major teas consumers?</content>
<content>Demitasse Ms was highly enjoyable!</content>
<content>Xalapa Lapa was great!</content>
<content>Aroma should consider selling Jamaican Butter Rum.</content>
<content>Darjeeling Special was not enjoyable at all.</content>
<content>Special Tips is my favorite.</content>
...
关于这两个查询
这两个查询虽然产生相同的结果,但是它们的执行过程稍微有些不同。
在 FLWOR 查询中,第二行指示 DB2 迭代 aroma.sales.comments 列中包含的 <Comments> 元素的 content 子元素。每个 content 元素依次被绑定到变量 $y。第三行表明,对于每次迭代,返回 $y 的值。结果是一系列的 XML 元素。
在路径查询中,第一步调用 db2-fn:xmlcolumn 函数获得 aroma.sales 表的 Comments 列中包含的 XML 文档的一个列表。第二步返回所有这些文档中的 <Comments> 元素,第三步返回嵌套在这些 <Comments> 元素中的 <comment> 元素,第四步返回嵌套在 <comment> 元素中的 <feedback> 元素,第五步返回嵌套在 <feedback> 元素中的 <content> 元素。
text() 函数
问题
Aroma 数据库中存储了哪些客户评论?将评论的内容显示为文本。
例子 FLWOR 查询
xquery
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback/content
return $y/text()
例子路径查询
xquery
db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback/content/text()
两个查询,一个结果
The employee named Heather Gray was very helpful.
What countries are major teas consumers?
Demitasse Ms was highly enjoyable!
Xalapa Lapa was great!
Aroma should consider selling Jamaican Butter Rum.
Darjeeling Special was not enjoyable at all.
Special Tips is my favorite.
...
关于这两个查询
这两个查询调用 text() 函数返回 XML 元素值的文本表示。
根据 XML 元素值进行过滤
问题
Aroma 数据库中存储了哪些客户建议?将它们显示为文本。
例子 FLWOR 查询
xquery
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback
where $y/type = "suggestion"
return $y/content/text()
例子路径查询
xquery
db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback[type =
"suggestion"]/content/text()
两个查询,一个结果
Aroma should consider selling Jamaican Butter Rum.
Aroma should consider selling Gyokuro Asahi Pearl Dew.
Aroma should consider selling Orange Pekoe.
Aroma should consider selling Vanilla Creme.
Aroma should consider selling China Yunnan.
Aroma should consider selling Kona Fancy 100%.
Aroma should consider selling Blackcurrant.
Aroma should consider selling Sencha.
...
关于这两个查询
XQuery 的 where 子句类似于 SQL 的 WHERE 子句。在 FLWOR 查询中,它根据 XML 文档的 type 元素的值对结果进行过滤。
for 子句将变量 $y 依次绑定到每个反馈。where 子句包含一个小型的路径表达式,这个路径表达式从每个 feedback 元素导航到嵌套在它里面的 type 元素。只有当这个 type 元素的值等于 "suggestion" 时,where 子句才为 true(返回内容)。
附加的谓词 [type = "suggestion"] 用于创建相应的路径查询。
问题
Aroma 数据库中存储了哪些客户建议和疑问?将它们显示为文本。
例子 FLWOR 查询
xquery
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback
where $y/type = "suggestion" or $y/type = "question"
return $y/content/text()
例子路径查询
xquery
db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback[type =
"suggestion"
or type = "question"]/content/text()
两个查询,一个结果
What countries are major tea consumers?
Aroma should consider selling Jamaican Butter Rum.
Aroma should consider selling Gyokuro Asahi Pearl Dew.
Who do you buy your tea from?
What is the maximum amount of coffee one person can safely consume per day?
Aroma should consider selling Orange Pekoe.
Aroma should consider selling Vanilla Creme.
...
关于这两个查询
和 SQL 一样,可以使用搜索条件来细化 XML 元素的选择。本系列的第 3 部分,使用 AND、NOT 和 OR 连接词创建复杂条件 对搜索条件和逻辑操作符作了详细的讨论。
转换 XML 输出
问题
哪些商店响应尚未完成?以 HTML 列表显示动作文本。
例子查询
xquery
<ul> {
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/store_response
where $y/completed = "no"
return <li>{$y/action/text()}</li>
} </ul>
结果
<ul>
<li>Thank you for your excellent suggestion! Aroma Coffee and Tea Company is actually
planning on ordering the product you've suggested--check our stores next month!</li>
<li>Please see our "All About Tea" page at www.aroma.com/tea</li>
<li>The Aroma Coffee and Tea Company supports local growers in North America as well
as imports. Our mission is to offer the best-quality coffee and tea products from North
America as well as around the world. All of our suppliers must meet all of our quality
control standards.</li>
<li>Thank you for your excellent suggestion! Currently, Aroma Coffee and Tea Company
does not plan to include the product you've suggested in our purchase plans. We will
keep your suggestion on file and we will consider it in the future.</li>
<li>Thank you for your excellent suggestion--we completely agree! Please visit
www.aroma.com.</li>
<li>Please see our "All About Coffee" page at www.aroma.com/coffee</li>
<li>Please see our "All About Tea" page at www.aroma.com/tea</li>
...
</ul>
注意: 为便于阅读,结果在格式上做了调整。DB2 Command Editor 实际上用一行显示整个列表。
关于该查询
XQuery 的一个强大之处是可以将 XML 输出从一种形式的 XML 转换成另一种形式。例如,可以使用 XQuery 检索存储的整个 XML 文档或它的一部分,然后将输出转换成 HTML,以便在 Web 浏览器中显示。例子查询检索商店响应,将其转换成 XML 元素,作为无序 HTML 列表的一部分。
查询的第二行将无序列表的 HTML 标记(<ul>)包括在结果中。它还引入了一个花括号,这是本查询中使用的两组花括号中的第一个花括号。花括号指示 DB2 计算和处理被括在其中的表达式,而不是将其当作文字字符串。
第三行迭代商店响应,将变量 $y 依次绑定到每个 store_response 元素。return 子句表明,在返回 store_response 元素之前,将其用 HTML 列表标记包围起来。最后一行结束查询,并完成 HTML 无序列表标记。
if-then-else 表达式
问题
哪些商店响应尚未处理完? 将评论 ID、客户信息和商店动作显示为 <suggestion> 和 <question> 元素下对应的 XML 元素。
例子查询
xquery
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment
where $y/store_response/completed = "no"
return
(
if ($y/feedback/type = 'suggestion')
then
<suggestion>
{$y/comment_ID,
$y/customer_info,
$y/store_response/action}
</suggestion>
else
<question>
{$y/comment_ID,
$y/customer_info,
$y/store_response/action}
</question>
)
结果
<suggestion>
<comment_ID>4201</comment_ID>
<customer_info>
<fname>Karen</fname>
<lname>Richardson</lname>
<phone>3546388558</phone>
<email>K.Richardson@hotmail.com</email>
</customer_info>
<action>Thank you for your excellent suggestion! Aroma Coffee and Tea Company
is actually planning on ordering the product you've suggested--check our stores
next month!</action>
</suggestion>
<question>
<comment_ID>9601</comment_ID>
<customer_info>
<fname>Thomas</fname>
<lname>Nelson</lname>
<phone>0055238541</phone>
</customer_info>
<action>Please see our "All About Tea" page at www.aroma.com/tea</action>
</question>
<question>
<comment_ID>15503</comment_ID>
<customer_info>
<fname>Joseph</fname>
<lname>Sanders</lname>
<phone>6717072487</phone>
<email>J.Sanders@gmail.com</email>
</customer_info>
<action>The Aroma Coffee and Tea Company supports local growers in North
America as well as imports. Our mission is to offer the best-quality coffee
and tea products from North America as well as around the world. All of our
suppliers must meet all of our quality-control standards.</action>
</question>
...
注意:为便于阅读,结果在格式上做了调整。实际上,DB2 Command Editor 每行显示一条结果。
关于该查询
可以将 XQuery 转换 XML 输出的能力与它内置的对条件逻辑的支持相结合,减少应用程序代码的复杂性。查询创建复杂的 XML 元素,位于 <suggestion> 和 <question> 元素下,其中包含关于评论 ID、客户信息和商店动作的信息。
这个结果对于执行商店响应的人来说很有用,他已经有了足够的信息来做他的工作。
要点: <comment_ID> 元素必须严格按照大小写拼写,因为 XQuery 是大小写敏感的。 |
Order By 子句
问题
Aroma 数据库中存储了哪些客户意见?按照商店评分从低到高排列。
例子查询
xquery
for $y in db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment
where $y/feedback/type = "opinion"
order by $y/store_rating/score
return
<comment>
<rating>{$y/store_rating/score/text()}</rating>
<opinion>{$y/feedback/content/text()}</opinion>
</comment>
结果
<comment>
<rating>2</rating>
<opinion>Darjeeling Special was not enjoyable at all.</opinion>
</comment>
...
<comment>
<rating>3</rating>
<opinion>Good store, but quality of customer service could be better.</opinion>
</comment>
...
<comment>
<rating>4</rating>
<opinion>The employee named Heather Gray was very helpful.</opinion>
</comment>
...
注意: 为便于阅读,结果在格式上做了调整。实际上,DB2 Command Editor 每行显示一条结果。
关于该查询
order by 子句规定返回的结果必须按照商店评分以升序(默认顺序)排序。
Let 子句
问题
Comments 列中存储了多少条客户意见?多少条建议?多少个疑问?
例子查询
xquery
for $t in distinct-values
(db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/feedback/type)
let $tc := db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment[feedback/type = $t]
return
<comments>
<type>{$t}</type>
<count>{count($tc)}</count>
</comments>
结果
<comments>
<type>opinion</type>
<count>1220</count>
</comments>
<comments>
<type>question</type>
<count>364</count>
</comments>
<comments>
<type>suggestion</type>
<count>251</count>
</comments>
注意:为便于阅读,结果在格式上做了调整。实际上,DB2 Command Editor 每行显示一条结果。
关于该查询
该查询计算每种类型有多少条评论。
let 子句用于将一个值(可能是由多个项目组成的一个列表)赋给一个变量, FLWOR 表达式的其他子句中可以使用这个变量。
for 子句中的 distinct-values 函数返回 Comments 列中的 <comments> 元素中的 type 元素出现的所有不同值的列表。有三种不同的 type 值:opinion、suggestion 和 question。for 子句将变量 $t 依次绑定到每种 type 值。对于 $t 的每个值,let 子句再次扫描 Comments 列,将变量 $tc 绑定到类型与 $t 中的 type 匹配的所有评论的一个列表。return 子句为每种不同的 type 值构造一个新的 <comments> 元素。每个 <comments> 元素包含两个子元素:一个是包含类型值的 <type> 元素,还有一个是包含指定类型的评论的数量的 <count> 元素。
count 函数是 XQuery 提供的大量内置函数中的一个。下一节会给出关于内置函数的更多例子。
内置函数
问题
所有评论中对商店的平均评分是多少?
例子查询
xquery
avg(db2-fn:xmlcolumn('AROMA.SALES.COMMENTS')/Comments/comment/store_rating/score)
结果
4.11389645776567
关于该查询
db2-fn:xmlcolumn 函数返回存储在 Comments 列中的所有评分的一个序列,avg 函数计算它们的平均值。
下面的表阐释了业务查询中常用的一些 XQuery 函数:
函数 | 描述 |
sum(sequence-expression) | 计算序列中所有值的总和 |
avg(sequence-expression) | 计算序列中所有值的平均值 |
max(sequence-expression) | 确定序列中的最大值 |
min(sequence-expression) | 确定序列中的最小值 |
count(sequence-expression) | 计算序列中非空值的个数 |
含嵌入式 SQL 的 XQuery 查询
问题
有哪些针对位于纽约的商店的评论?将评论的内容显示为文本。
例子查询
xquery
for $y in
db2-fn:sqlquery(
'SELECT Comments
FROM aroma.sales a, aroma.store b
WHERE city = ''New York''
AND a.storekey = b.storekey')/Comments/comment/feedback/content/text()
return $y
结果
Does drinking too much tea cause any health problems?
How to differentiate from imitations?
Is there a maximum amount of tea one person can safely consume per day?
Aroma should consider selling Indonesian House Roast.
Darjeeling Special was very good.
Irish Breakfast was great!
...
关于该查询
这个查询将 SQL 嵌入在 XQuery 中,以便根据 SQL 数据值限制结果。这里没有使用 db2-fn:xmlcolumn 函数返回一个表的一列中所有的 XML 数据,而是调用 db2-fn:sqlquery 函数,后者执行一个 SQL 查询,只返回选中的数据。传递给 db2-fn:sqlquery 的 SQL 查询必须返回 XML 数据。然后,XQuery 可以进一步处理返回的 XML 数据。
查询的 SQL 部分连接 Sales 表和 Store 表。它检索 Sales 表中与在纽约的商店有相同 storekey 的行。存储在这些行中的 Comments 文档成为一个路径表达式的输入,该路径表达式以文本的形式返回文档中包含的所有 content 元素。
要点:SQL 查询的 WHERE 子句将 city 值与字符串 "New York" 进行比较。在 SQL 中,这样的字符串是以单引号括起的。注意,虽然这个例子看上去是使用了双引号,但实际上是在比较值的前后用了两个单引号(''New York'')。"额外"的单引号是换码符。如果在基于字符串的查询谓词的前后使用双引号,而不是使用两对单引号,那么就会出现语法错误。 |
结束语
本教程对 XML 和 XQuery 做了基本的概述,讨论到了以下问题:什么是 XML?它有哪些优点?何时应该使用 XML?
然后,本教程向读者展示了如何使用基本的 Query 查询来检索 XML 元素、过滤数据、转换数据、格式化数据和使用数据。
XQuery 和 SQL 并不是相互排斥的,它们可以联合起来,形成功能更强大的查询。
本教程只对 XML 和 XQuery 做最基本的介绍。
本教程是这个 系列 中的最后一个部分。再次感谢您选择 IBM DB2 9 来了解服务于关系结构和 pureXML 结构的数据的混合型数据服务器。
本文示例源代码或素材下载
- ››SQL Server 2008 R2 下如何清理数据库日志文件
- ››sqlite 存取中文的解决方法
- ››SQL2005、2008、2000 清空删除日志
- ››SQL Server 2005和SQL Server 2000数据的相互导入...
- ››sql server 2008 在安装了活动目录以后无法启动服...
- ››sqlserver 每30分自动生成一次
- ››sqlite 数据库 对 BOOL型 数据的插入处理正确用法...
- ››sql server自动生成批量执行SQL脚本的批处理
- ››sql server 2008亿万数据性能优化
- ››SQL Server 2008清空数据库日志方法
- ››sqlserver安装和简单的使用
- ››SQL Sever 2008 R2 数据库管理
更多精彩
赞助商链接