引言 本文提供了使用 DB2 pureXML 查询 XML 数据的快速参考。本文回顾了与一些常见查询相关的语法,包括 XQuery with SQL 格式和 SQL/XML with XQuery 格式。甚至是在这两种格式之间选择时,也可以多种方式编写大多数查询,并获得同样的结果。 本文主要面向熟悉 XML 的软件架构师、设计人员和开发人员。本文假设您正在使用 IBM 开发工具,比如 Rational® Software Architect、Rational Application Developer、Optim® Development Studio 或 InfoSphere™ Data Architect,在 DB2 中处理 XML 数据。 搭建环境 首先搭建处理查询的环境。 访问模板 本文中每个查询示例的语法都来自 IBM 工具提供的编辑器模板。要访问这些工具的模板集,请完成以下步骤: 导航到 Window > Preferences。 在 Preferences 中,导航到 Data Management > SQL Development > SQL and XQuery Editor > Templates,如图 1 所示。 查看可用的模板,导入由其他产品提供的模板,或者更新模板并将它们导出,与其他人共享。 图 1. SQL 和 XQuery 模板视图
 查看原图(大图) 编辑 SQL 或 XQuery 脚本时,在编辑器窗口中按 CTRL+空格 组合键,可访问并使用可用的模板。 设置数据库表 本文的示例使用 SAMPLE 数据库,该库中的 XML 数据由 DB2 提供。可以将这些示例安装为 DB2 First Steps 的一部分,如图 2 所示。也可以在安装后在命令行输入 db2sampl -xml。
图 2. 使用 First Steps 配置示例数据
 查看原图(大图) 本文的示例查询使用 SAMPLE 数据库的 CUSTOMER 表,如图 3 所示。 图 3. SAMPLE 数据库中 CUSTOMER 表的视图
 清单 1 显示了一个示例 XML 文档,该文档可在 CUSTOMER 表的 INFO 列中找到。 清单 1. INFO 列 <customerinfo Cid="1001"> <name>Kathy Smith</name> <addr country="Canada"> <street>25 EastCreek</street> <city>Markham</city> <prov-state>Ontario</prov-state> <pcode-zip>N9C 3T6</pcode-zip> </addr> <phone type="work">905-555-7258</phone> </customerinfo>
使用 XQuery 创建查询 本节介绍使用 XQuery 如何创建查询。 XQuery 表达式的类型 下列列表显示了可在同一查询中使用的一些不同类型的 XQuery 表达式。 主 使用语言的基础基元,包括文本、变量引用、括号表达式和函数调用等。 路径 使用 XPath 2.0 的语法识别 XML 树中的节点。
FLWOR 迭代序列,并将变量绑定到中间结果。 比较 比较两个值。 构造函数 在查询内部创建 XML 结构。 逻辑 使用 and/or 计算布尔型值。 条件 使用 if、then 和 else 评估测试表达式的值是 true 还是 false。 基本查询 使用 XQuery 在 DB2 中查询 XML 数据有两种基本方法。您可以使用 DB2 sqlquery 函数以使用 SQL 访问具体 XML 数据,或者使用 DB2 xmlcolumn 函数以使用 XQuery 访问列中的所有 XML 数据。清单 2 显示了基本语法。 清单 2. 基本语法 xquery db2-fn:sqlquery(${sql_query})${xquery_expression}
清单 3 显示了一个简单的查询,在其中可使用 SQL 返回 INFO 列的文档的子集。在查询的末尾,包含一个从 XML 文档内部检索 name 元素的 XPath 表达式。 清单 3. 返回文档的子集 xquery db2-fn:sqlquery("select INFO from CUSTOMER where CID = 1000")/customerinfo/name
在本例中,您对 INFO 列中的所有 XML 文档都感兴趣。对于每个文档,您使用路径表达式返回 name 元素。 清单 4 显示了 xmlcolumn 语法。 清单 4. XMLcolumn 语法 xquery db2-fn:xmlcolumn('${schema}.${table}.${column}')${xquery_expression}
清单 5 展示了 INFO 列中的所有 XML 文档。对于每个文档, 您使用路径表达式返回 name 元素。 清单 5. INFO 列中的 XML 文档 xquery db2-fn:xmlcolumn('CUSTOMER.INFO')/customerinfo/name
FLWOR 使用 XQuery 的常见方法是编写包含下列子句的查询,其中一些子句是可选的:For、Let、 Where、Order by 和 Return。这些简称为 FLWOR(读音为 flower)。 记住,XQuery 希望得到 XML 输出并且返回 XML。语法如清单 6 所示。
清单 6. FLWOR 语法 xquery for $$i in ${xquery_expression} let $$x := ${xquery_expression} where ${xquery_expression} order by ${xquery_expression} return ${xquery_expression}
清单 6 中的语法包括所有可用的 FLWOR 表达式元素。下面是一些示例,这些示例表明您可以使用可选元素修改查询的结构。 清单 7 是简单 FLOWER 查询的一个示例,为每个 customerinfo 元素检索与每个 address 相关的 city 元素。 清单 7. 简单的 FLWOR xquery for $c in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo return $c/addr/city
清单 8 为上一个查询添加了一个限制,仅为具有属性 Cid = 1001 的 customer 返回 city。 清单 8. 返回 city 的 FLWOR xquery for $c in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo where $c/@Cid = 1001 return $c/addr/city
清单 9 提取 prov-state 是 Ontario 的客户的名称,并根据 name 的字母顺序排列结果。 清单 9. 查询 Ontario 的 FLWOR xquery for $c in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo where $c/addr/prov-state = "Ontario" order by $c/@name return $c/name
清单 10 使用 Let 分配变量,保留居住于 Canada 的客户的 pcode-zip 值,然后按照 Cid 的字母顺序排列结果。然后代码构造一个新 XML 元素 <contact>,该元素包括 Cid 和 pcode-zip。 清单 10. 查询 pcode-zip 的 FLWOR xquery for $c in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo let $pc := $c/addr/pcode-zip where $c/addr/@country = "Canada" order by $c/@Cid return <contact>{$c/@Cid}{$pc}</contact>
这些查询示例相当简单,并且不支持命名空间。要支持命名空间,可以将命名空间添加到查询列出的元素中; 或者可以使用命令 declare default element namespace '${namespace_uri}'; 声明默认命名空间。 清单 11 显示了使用命名空间声明的一个 XML 文档。 清单 11. 具有命名空间的 XML 文档 <customerinfo xmlns="http://poindustry.org" Cid="1001"> <name>Kathy Smith</name> <addr country="Canada"> <street>25 EastCreek</street> <city>Markham</city> <prov-state>Ontario</prov-state> <pcode-zip>N9C 3T6</pcode-zip> </addr> <phone type="work">905-555-7258</phone> </customerinfo>
由于正在处理的是一个具有单一命名空间声明的简单示例, 因此可使用两种方法中的任意一种查询此文档。 清单 12 声明了默认命名空间。您无需将查询中的元素引用更改为包含命名空间, 因为默认情况下,它们会访问此单一命名空间。 清单 12. 默认命名空间 xquery declare default element namespace = "http://poindustry.org"; for $c in db2-fn:xmlcolumn("CUSTOMER.INFO")/customerinfo return $c/addr/city
通过定义用作命名空间快速引用的命名空间前缀(比如 cust-ns), 清单 13 利用了多个命名空间。定义了命名空间之后,结合使用此命名空间前缀和引用的任意元素名称。 清单 13. 命名空间前缀
xquery declare namespace cust-ns = "http://poindustry.org"; for $c in db2-fn:xmlcolumn("CUSTOMER.INFO")/cust-ns:customerinfo return $c/cust-ns:addr/cust-ns:city
对于清单 12 和清单 13 中的命名空间示例,记住,分号是一种典型的查询语句结束符。 使用命名空间时,将语句结束符更改为一个不同的字符,比如井号(#)。 转换和更新 本节介绍更新 XML 文档中具体内容(元素或属性)的查询。介绍的查询使用了 XQuery Update Facility,这是 XQuery 1.0 的语言和语义的更新。可使用此类型的查询更新、替换、删除 XML 文档的内容,也可以将内容插入 XML 文档中。 这种更改适用于数据库的数据或查询返回的数据。不同操作的查询语法稍有不同。清单 14 显示了替换查询的一个基本语法示例。 清单 14. 基本语法(替换) UPDATE ${table} SET ${xml_col} = XMLQUERY(' transform copy $$x := ${xquery_expression} modify do replace value of ${xquery_expression} with ${xquery_expression} return ${xquery_expression}') WHERE ${expression}
下面是修改语法以显示对其他转换操作支持的示例。 清单 15 更新了具体客户的 city 元素值。注意, transform 是查询的可选部分。所以可在后续一些示例中忽略它。 清单 15. 替换示例 UPDATE customer SET info = XMLQUERY(' transform copy $c := $INFO modify do replace value of $c/customerinfo/addr/city with "Toronto" return $c') WHERE CID =1001
清单 16 删除了具体客户的 city 元素。 清单 16. 删除示例 UPDATE customer SET info = XMLQUERY(' copy $c := $INFO modify do delete $c/customerinfo/addr/city return $c') WHERE CID =1001
插入很有趣,因为您需要说明在文档的何处插入信息。 清单 17 没有说明在文档的何处插入新元素。实际插入位置是不确定的。 清单 17. 插入示例 UPDATE customer SET info = XMLQUERY(' copy $c := $INFO modify do insert <city>Toronto</city> into $c/customerinfo/addr return $c') WHERE CID =1001
如果您需要具体位置,可查看插入数据的许多可选方法之一。 清单 18 在 phone 元素后插入了数据。 清单 18. 在元素后插入数据的示例 UPDATE customer SET info = XMLQUERY(' copy $c := $INFO modify do insert <phone type="cell">905-555-7272</phone> after $c/customerinfo/phone return $c') WHERE CID =1001
清单 19 在 addr 内插入了一个作为首个子元素的元素。 清单 19. Insert first 示例 UPDATE customer SET info = XMLQUERY(' copy $c := $INFO modify do insert <company-name>ACME Co</company-name> as first into $c/customerinfo/addr return $c') WHERE CID =1001
清单 20 在 addr 内插入了一个作为最后一个 子元素的元素。
清单 20. Insert last 示例 UPDATE customer SET info = XMLQUERY(' copy $c := $INFO modify do insert <company-name>ACME Co</company-name> as last into $c/customerinfo/addr return $c') WHERE CID =1001
清单 21 在文档的 addr 元素前添加了一个元素。 清单 21. Insert before 示例 UPDATE customer SET info = XMLQUERY(' copy $c := $INFO modify do insert <email>ksmith@acme.com</email> before $c/customerinfo/addr return $c') WHERE CID =1001
清单 22 通过将 addr 元素更改为 address 重命名了现有元素。 清单 22. 重命名示例 UPDATE customer SET info = XMLQUERY(' copy $c := $INFO modify do rename $c/customerinfo/addr as "address" return $c') WHERE CID =1001
清单 23 显示了一个转换查询,该查询仅修改了查询结果,并未更改数据库的内容。 清单 23. XQuery 重命名示例 xquery copy $c := db2-fn:sqlquery('select INFO from CUSTOMER where CID =1001') modify do rename $c/customerinfo/addr as "address" return $c
使用 SQL/XML 创建查询 本节提供了使用 SQL/XML 创建查询的示例。 基本 SQL/XML 查询 一个好的出发点是查看 SQL/XML 查询的精简语法,如清单 24 所示。 清单 24. SQL/XML 查询的语法
SELECT XMLQUERY('${xquery_expression}') FROM ${table_name} WHERE XMLExists('${xquery_expression}')
有几种方法可以使用具有不同类型的 XQuery 表达式的语法。首先查看包含路径表达式的一个示例。 清单 25 显示了一个查询,此查询获取居住于 city Markham 的客户的 name。XMLExists 谓词用于确定 XQuery 表达式返回一个还是多个项序列。注意,您需要使用方括号 ([ ]) 括住 XQuery 表达式内的任何值谓词。这样做可确保对表达式的评估与语义预期的一样。如果您省略了此方括号,则 XQuery 表达式的结果总会返回一个序列,并使 XMLExists 总是为 true。 清单 25. 使用谓词 SELECT XMLQUERY('$INFO/customerinfo/name') FROM CUSTOMER WHERE XMLEXISTS('$INFO/customerinfo/addr[city= "Markham"]')
接下来,查看另一个示例 FLOWER 表达式和 XMLQUERY 的基本示例。 清单 26 属性为 Cid > 1002 的客户的 addr 元素,其中 country = "Canada"。 清单 26. FLWOR 和 XMLQUERY SELECT XMLQUERY('for $i in $INFO/customerinfo/addr return $i') FROM CUSTOMER WHERE XMLEXISTS('let $i := $INFO/customerinfo where $i/@Cid > 1002 and $i/addr/@country = "Canada" return $i')
XMLTable 有时当您需要根据 XML 文档的信息返回关系表时,可使用 XMLTable 生成此结果。 XMLTable 语法如清单 27 所示。 清单 27. XMLTable 语法 SELECT X.${new_col1_name}, X.${new_col2_name}, ${table}.${col} FROM XMLTable(${row_generating_xquery_expression} COLUMNS ${new_col1_name} ${new_col1_data_type} PATH '${column_generating_xquery_expression}', ${new_col2_name} ${new_col2_data_type} PATH '${column_generating_xquery_expression}' ) AS X
清单 28 提供了一个使用 XMLTable 的简单示例。您正在基于 XML 文档的两个值返回行。 XML 文档返回的两个元素都显示在自己的列中。使用 X.* 表明您想返回 XMLTable 提供的所有列。 清单 28. 使用 X* SELECT X.* FROM customer, XMLTABLE('$INFO/customerinfo' COLUMNS custname VARCHAR(20) PATH 'name', city VARCHAR(20) PATH 'addr/city') AS X
除了根据 XML 文档的信息返回列之外,还可以从关系数据返回列,如清单 29 所示。 清单 29. 从关系数据返回列 SELECT customer.CID, X.* FROM customer, XMLTABLE('$INFO/customerinfo' COLUMNS custname VARCHAR(20) PATH 'name', city VARCHAR(20) PATH 'addr/city') AS X
清单 30 添加了一个新 XML 类型的列,其中可立刻构建一个新 XML 文档。 清单 30. 添加新列 SELECT customer.CID, X.* FROM customer, XMLTABLE('$INFO/customerinfo' COLUMNS custname VARCHAR(20) PATH 'name', city VARCHAR(20) PATH 'addr/city', newXML XML PATH '<newXML>{addr/pcode-zip}</newXML>') AS X
结束语 本文提供了使用 XML 数据和 DB2 pureXML 时的查询选项快速概述。 目的是为您提供快速熟悉 DB2 pureXML 的简单可访问参考。与学习其他编程语言一样,提高技能的最好方法是编写查询。 |