本文标签:数据库 DB2
简介 DB2 UDB Version 8.x 中的 XML 支持基于 DB2 的关系基础设施 。XML 数据要么按原样存储为字符大对象(CLOB),要么分解到关系表中 。另一方面,DB2 UDB Viper 具有真正的 XML 数据本机支持 。现在,将 XML 数据作为一种新的数据类型处理,存储在一个经过解析并加上注释的树中,这个树是与关系数据存储分开的 。还引入了基于 XML 模式的 XML 索引技术,并支持 XQuery 和 SQL/XML 作为查询和发布 XML 数据的语言 。 DB2 UDB Version 8.x 中的 XML 支持 DB2 8.x 使用 SQL/XML 和 DB2 XML Extender 向底层关系数据提供 XML 功能 。DB2 XML Extender 提供许多用户定义类型(UDT)、用户定义函数(UDF)和存储过程来支持 XML 。XML 文档存储为关系形式,并使用 XML Extender 基础设施为关系数据提供 XML 表现形式 。还支持一些用来将关系数据发布为 XML 的 SQL/XML 函数 。更多细节可以在 DB2 XML Extender Web 站点上找到 。 DB2 还允许创建用户定义的 Java 函数和存储过程,可以将 XML 和 XSL 解析器(作为 DB2 8.x 的一部分安装)合并到代码中 。 DB2 Viper 中的 XML 支持 DB2 Viper 支持本机 XML 存储,从而不再需要将 XML 分解到关系表中供查询和发布 。这种新的存储方式将 XML 保存为与 XML 文档对象模型(DOM)相似的经过解析并加上注释的树形式 。对于仍然需要将 XML 数据分解到关系表中的应用程序,这个版本中还提供了增强的分解功能,这种功能使用带注释的 XML 模式映射 。 XML 特性对比 —— DB2 UDB Version 8.x 和 DB2 Viper 表 1. XML 特性对比 —— DB2 UDB Version 8.x 和 DB2 Viper
|
DB2 UDB Version 8.x |
DB2 Viper |
存储和索引
|
XML 数据存储为两种形式: 原样的文档:
- XMLCLOB、XMLVARCHAR、XMLFILE 类型的 XML Extender 列 。
- BLOB、CLOB 或 VARCHAR 类型的列 。
- 在关系副表中创建 XML 文档的间接索引 。
分解到关系 XML Extender(XML 集合):
- 只有 XML 中的叶节点可以分解并映射到 SQL 列类型 。
|
XML 数据存储为两种形式: 原样的本机文档 XML 存储 。
- 从头构建了全新的层次化(本机)存储 。这种存储方式保存文档的任意树形式 。
- XML 类型的列 。
- 使用叶节点的路径表达式建立 XML 索引 。
- 在插入时对文档进行解析 。
用关系 SQL/XML 函数和带注释的模式映射进行分解 。
- 使用带注释的 XML 模式映射分解到现有的关系表 。
- XML 片段也可以分解,映射到 XML 列类型 。
- 处理名称空间 。
- 可以使用扩展的功能过滤 XML 数据,比如 DB2 表达式和条件 。
|
验证 |
- DAD 中定义的隐式验证 。
- 使用 XML Extender UDF svalidate 进行显式验证 。
- 文档类型定义(DTD)注册并存储在内部表中 。
- 从文件系统获得 XML 模式 。
|
- 使用 SQL/XML 函数 XMLVALIDATE 进行显式验证 。
- DTD 和 XML 模式注册在 XML 模式存储库(XSR)中,并存储在数据库中 。
|
查询和发布
|
使用 SQL/XML 和 XML Extender 函数进行查询和发布 。 对于原样的 XML 文档 。
- 使用带索引的副表查询文档,以 CLOB 形式获得文档 。
- 可以使用 XML Extender 函数进行子文档查询 。
可以使用 Extender 函数进行 XSLT 转换 。 对于分解到关系表的 XML 数据 。
|
使用 SQL/XML 和 XQuery 进行查询和发布 。 对于原样的 XML 文档 。
- 可以混合使用 SQL/XML 和 XQuery 来检索和发布关系数据和 XML 数据 。
使用 XML Extender XSLT 函数支持 XSLT 。
- 可以使用 XQuery 查询、转换和发布 XML 。
对于分解到关系表的 XML 数据 。
|
更新 |
对于原样的 XML 文档 。
- 使用 SQL update 语句进行全文档更新 。
- 使用 XML Extender UDF update 进行更新 。
|
对于原样的 XML 文档 。
- 使用 SQL update 语句进行全文档更新 。
- 由于缺少定义 XQuery 更新的标准,不支持子文档更新 。
- 可以从 developerWorks 下载更新存储过程,请参考 XML application migration from DB2 8.x to DB2 Viper, Part 1: Partial updates to XML documents in DB2 Viper (developerWorks,2006 年 5 月) 。
|
为数据库启用 XML 功能 |
需要为数据库启用 XML Extender 功能 。 |
不需要启用数据库,因为 XML 支持现在是 DB2 引擎的固有部分 。 |
工具 |
在 DB2 Development Center 或 Control Center 中没有集成 XML 支持 。 Websphere Studio Application Developer
- Java Database Connectivity(JDBC)驱动程序中没有提供支持 。
|
XML 支持集成到了工具的各个方面 。 DB2 Control Center 和 DB2 Developers Workbench(基于 Eclipse) 。
- Visual Studio .NET 增加了对 DB2 XML 的支持
|
DB2 版本 |
DB2 UDB Version 7.x 和 DB2 UDB Version 8.x DB2 z/OS Version 7 和更高版本(V8) iSeries V5R1 和更高版本(V5R3) |
DB2 Viper AIX、NT、LINUX、SOLARIS | 注意: 数据库中紧密集成了 XQuery 引擎,支持本机 XML 存储,因此能够获得 SQL 和 XQuery 两者的查询执行计划 。 DB2 UDB Viper 中引入的 XML 特性 在开始一步步地迁移示例应用程序之前,先简要地看看 DB2 UDB Viper 的 XML 支持 。 XML 数据的存储 在与 DB2 的本机 XML 支持进行交互时,图 1 中所示的抽象是关系表中一个 XML 类型的列 。任何良构的 XML 文档都可以插入这个列 。在物理存储层,主存储单元是一个节点 。 对于同时包含关系列和 XML 列的表,关系列存储为关系格式,XML 列存储为经过解析的树 。 图 1. 与 DB2 的本机 XML 支持进行交互
XML 索引 XML 索引是一种新型索引,可以高效地计算 XML 路径表达式,从而提高查询 XML 文档的性能 。 XML 索引使用一个 XMLPATTERN(没有谓词的 XPath,只有一个子轴(/)和后代或本身轴(//))来对一个 XML 列中存储的 XML 文档的路径和值建立索引 。在创建索引时,可以指定要为什么路径建立索引以及类型 。在此列中存储的 XML 中,与路径表达式或路径表达式集合匹配的任何节点都被索引 。索引直接指向存储中的节点,节点与它的父节点和子节点链接,便于快速导航 。
create index idx3 on dept(deptdoc) generate key using xmlpattern /dept/employee/name as sql varchar(35);
| XML 模式存储库 XSR 是一个存储库,存储着用来验证和处理 XML 列中存储的 XML 实例文档的所有 XML 工件 。XSR 避免了定位外部文档所需的额外开销以及可能产生的性能影响 。每个数据库的数据库编目中包含一个 XML 模式存储库,并包含编目表、编目视图和一些系统定义的存储过程(用于进行注册)以便将数据输入这些编目表 。XML 模式、DTD 和外部实体必须显式地在 XSR 中注册,然后才能使用 。 带注释的模式映射 DB2 Viper 使用带注释的 XML 模式提供一种新的分解机制 。并不创建单独的映射文件(DAD),而是用关系映射信息对 XML 模式进行注释 。然后,将这些带注释的模式注册到 XSR 。在运行时使用它们对要插入列中的 XML 文档进行分解 。分解的 XML 值的数据类型是标准关系类型 。可以使用关系索引技术为分解的关系列创建索引 。更多信息请参考 “From DAD to annotated XML schema decomposition” (developerWorks,2006 年 4 月) 。 图 2 给出一个带注释的模式映射示例 。它展示整个 XML 文档以及从 XML 文档提取出的数据如何存储在同一个记录中 。 图 2. 带注释的模式映射
原样的 XML 文档存储在 XMLPO 列(XML 类型)中,提取出的 orderID 存储在 ORDERID 列(VARCHAR)中,orderDate 存储在 ORDERDATE 列(DATE)中 。 SQL/XML 函数 XML 发布函数 文档构造过程就是用元素和属性这样的小块内容组合出 XML 值 。SQL/XML 为这个过程提供了几个函数,可以从关系数据构造出 XML 文档 。 DB2 UDB Version 8.x 中有以下这些用来发布的 SQL/XML 函数:
XMLAGG: 以提供的 XML 值作为输入,返回所有非空的输入 XML 值的连结 。XMLATTRIBUTES: 生成被构造的 XML 元素的属性 。XMLCONCAT: 连结非空的 XML 类型的输入表达式,返回一个 XML 值序列 。XMLELEMENT: 根据输入参数构造一个 XML 元素 。XMLFOREST: 从输入参数构建一个 XML 元素林 。XMLNAMESPACES: 为由 XMLELEMENT 或 XMLFOREST 生成的元素构造名称空间声明 。XML2CLOB 和 XMLSERIALIZE: XML 串行化函数将 XML 值转换为一个字符串值 。 |
图 3. DB2 UDB V8.x 中的 SQL/XML 发布函数
DB2 Viper 支持 DB2 V8 中的所有 SQL/XML 函数(并接受或返回新的 XML 类型) 。 还支持以下这些新的 SQL/XML 发布函数:
XMLCOMMENT: 生成一个 XQuery 注释节点 。XMLPI: 生成一个 XQuery 处理指令节点 。XMLTEXT: 生成一个 XQuery 文本节点 。XMLDOCUMENT: 生成一个 XQuery 文档节点 。 |
下面是用于 IN/OUT 和验证的新的 SQL/XML 函数:
XMLPARSE: 对字符/BLOB 数据进行解析,并生成 XML 值 。XMLCAST: 转换为 XML 类型,或者相反 。XMLVALIDATE: 针对 XML 模式和类型验证 XML 值,并给 XML 值加注释 。IS VALIDATED: 检查 XML 值是否已经经过验证 。 |
XMLPARSE 可以使用 SQL/XML 函数 XMLPARSE 将表示 XML 文档的字符串值转换为 DB2 XML 类型 。这个函数接受一个串行化的 XML 文档,将它转换为 XML 类型的实例 。当需要改变默认的解析选项时,使用 XMLPARSE 。使用 XMLPARSE 会使系统 “忘记” 正在处理 XML 数据,因为 XMLPARSE 的输入是一个字符串或二进制类型 。
insert into customer (cid, info) values (?,XMLPARSE( DOCUMENT cast(? as BLOB(2M)) preserve whitespace ))
| XMLCAST 这个伪函数将 XML 值转换为非 XML 数据类型,或者将非 XML 值转换为 XML 值 。例如,它将 SQL/XML 值转换为 SQL 数据类型 。它支持转换为 SQL 标量类型的子集 。假设转换的源来自 XML 模式原子类型或无类型文本,或者是值为原子类型或无类型文本的节点 。
values(XMLCAST(XMLQUERY($m/customer/@cid PASSING xmlparse(document hardeep singh) AS "m") AS INTEGER) )
| XMLValidate XMLValidate 函数接受一个 XML 值并针对一个 XML 模式验证它,返回一个用 XML 模式中定义的默认值和类型注释生成的 XML 值 。对于本机 XML 列,没有列级的 XML 模式验证 。验证必须显式地添加到每个 insert 或 update 语句中 。这允许将来自不同 XML 模式的 XML 文档保存在相同的列中 。 注意: 不支持针对 DTD 进行验证 。DTD 只用来添加默认值和解析实体引用 。
insert into purchaseOrders (pid,porders) values (2, XMLValidate(?))
| Is validated is validated 谓词可以用来检查 XML 数据是否已经经过验证 。它用于检查约束和在 WHERE 子句中对行进行过滤,而且不会受到用来验证的 XML 模式的影响 。
Alter table purchaseOrders add constraint xml_check check (pOrder is validated)) Select pOrder from purchaseOrders where pOrder is validated
| XMLSERIALIZE XML 值在处理时采用一种内部表示方式,这不是字符串,也不能直接与字符串值进行比较 。可以使用 XMLSERIALIZE 函数将 XML 值转换为表示 XML 文档的串行化字符串值 。在 DB2 驱动程序不支持 XML 类型的环境中,这个函数非常有用 。 XMLSERIALIZE 函数返回一个从 XML 表达式参数生成的指定数据类型的串行化 XML 值 。结果的数据类型由用户指定 。如果 XML 表达式的结果是空的,那么函数的结果是空值 。返回的串行化 XML 值必须小于 2GB 。串行化结果用 UTF-8 进行编码 。
SELECT XMLSERIALIZE ( CONTENT XMLELEMENT ( NAME "customer", XMLATTRIBUTES (e.cid AS "id"), XMLELEMENT (NAME "name", e.name), XMLELEMENT (NAME "email", e.email), XMLELEMENT (NAME "zip", e.zip)) AS CLOB(7200)) AS CINFO FROM customer e where cid=1000
| 下面是用来查询 XML 数据的新的 SQL/XML 函数和谓词:
XMLTABLE: 执行一个 XQuery,将结果序列作为关系表返回 。XMLEXISTS: 判断一个 XQuery 是否返回一个或多个项 。XMLQUERY: 执行一个 XQuery 并返回结果序列 。 | XMLTABLE 从 XML 文档构造一个表 XMLTABLE 提供了从 XML 文档发布关系数据的标准方式 。它查询 XML 值并返回一个关系结果集(将 XML 数据分解为关系形式) 。创建一个虚拟表作为分解的结果,可以使用 SQL insert 语句将这个表插入现有的 SQL 表 。 XMLTABLE 允许指定生成的关系的形态(列的数量和数据类型) 。XQuery 参数决定行实例和每列的值的生成 。 图 4. XMLTABLE 查询
图 4 所示的查询接受输入的 XML 文档(product)并从其中分解出 @pid 和根节点 。然后将这些存储进 XMLPRODUCT 表中 。 表 2. 带注释的 XML 模式分解和 XMLTABLE 之间的差异
|
带注释的 XML 模式分解 |
XMLTABLE(SQl/XML) |
类型映射 |
静态映射信息在 XML 模式中注释并在注册时启用,不需要在运行时向应用程序公开(隐式) 。 |
动态映射信息作为 SQL 查询的一部分 。实际上,映射在运行时显式地定义并向应用程序公开 。 |
XML 模式 |
需要一个 XML 模式,而且这个 XML 模式必须在 XSR 中注册 。 |
不需要一个 XML 模式 。 |
目标关系表必须存在? |
是的 。 |
在运行时创建虚拟表 。 |
支持多个表? |
是的 。一个 XML 文档可以映射到多个关系表 。 |
不行 。只能创建一个可以在 SQL 语句中引用的虚拟表 。 | XMLQUERY XMLQUERY 是一个 SQL/XML 发布(伪)函数,它的用途是计算一个 XQuery 表达式并向应用程序返回一个 XML 值,这个值可以是包含零个或更多项的 XQuery 序列 。 图 5. XMLQUERY 查询
图 5 所示的查询只返回 XMLPRODUCT 表中每一行的 DESCRIPTION 列中存储的 XML 数据的一些元素 。 XMLEXISTS XMLEXISTS 谓词使用 XQuery 查询一个 SQL/XML 值 。如果查询返回非空的序列,那么函数返回 true;否则返回 false 。 图 6. XMLEXISTS 查询
DB2 Viper 的 XML 支持对基于 XML 的应用程序的影响 应用程序的设计会受到 XML 数据的存储模型(原样或分解)的影响 。存储模型受到存储、查询和修改 XML 数据方面的功能限制和任何性能需求的影响 。随着新功能的引入,DB2 XML Extenders 的许多限制已经被消除了,因此 XML 存储模型可以改变了 。 本文的其余部分详细描述处理 XML 数据的 DB2 功能之间的差异 。还讨论如何将现有的应用程序迁移到 DB2 Viper 以便使用新的特性集 。 设置数据库 您可能会注意到,为数据库设置 XML 支持所需的一些步骤已经改变了 。 表 3. DB2 V8.x 和 DB2 Viper 数据库设置之间的差异
|
DB2 UDB Version 8.x |
DB2 Viper |
创建数据库
|
也支持非 UTF-8 数据库使用 XML 数据 。 为创建数据库,发出 create db migrate 命令 。 |
只支持 UTF-8 数据库使用 XML 数据 。 为创建 UTF-8 数据库,发出 create db migrate using codeset utf-8 territory us 命令 。 |
为数据库启用 XML |
需要通过发出 dxxadm enable_db migrate 命令为每个数据库启用 XML Extender 支持 。 |
XML 支持是 UTF-8 数据库固有的功能 。 |
安装进行验证所需的任何 DTD 或 XML 模式 |
用来进行验证的所有 XML 模式位于文件系统中,不进行注册 。 用来进行验证的任何 DTD 需要注册并存储在数据库的特殊表 DTD_REF 中 。
|
用来进行验证的所有 XML 模式需要注册在 XSR 中 。 DTD 不能用于验证,所以在大多数情况下 DTD 必须改为 XML 模式(仍然可以将它们注册在 XSR 中,因为它们可以用于实体引用和默认值) 。 |
创建 XML 到关系数据的映射 |
原样存储(XML 作为 XML CLOB 存储在一个列中)和分解存储(XML 中的数据分解存储到关系表中)都需要 XML 到关系数据的映射 。 使用专用的映射形式,DAD 。 |
只有分解存储需要 XML 到关系数据的映射 。使用更标准且高效的映射技术,带注释的 XML 模式映射 。
|
注册并启用映射 |
存储原样 XML 的 XML 列需要使用 DAD 映射来启用,从而创建更新与此列相关联的副表所需的触发器 。启用 XML 列的命令是:db2xml.dxxEnableColumn 。 DAD 映射定义如何将 XML 文档分解为关系表集合(XML 集合),可以注册 DAD 映射并允许在 XML Extender 分解函数中使用 。启用 XML 集合的命令是:db2xml.dxxEnableCollection 。 |
XML 类型的列(存储本机 XML 数据)没有任何相关联的映射,不需要启用 。 带注释的 XML 模式定义如何将 XML 文档分解为关系表,需要将它们注册在 XSR 中并启用分解 。这可以在注册时进行: COMPLETE XML SCHEMA PRODSCHEMA ENABLE DECOMPSITION 也可以在已经注册 XML 模式之后启用: ALTER XSROBJECT PRODSCHEMA ENABLE DECOMPOSITION |
在 XML 文档上创建索引 |
对于 XML 列中的原样文档,可以建立间接索引,办法是:将 XML 文档中的部分数据分解到辅助(副)关系表中,然后为这些表创建索引,从而对分解的数据进行快速搜索 。 注意: 实际上,这些映射定义 XML 列上的模式种类,如果输入文档的形态改变了,那么需要修改映射信息和副表 。 |
以本机方式存储在 XML 列中的 XML 文档可以建立 XML 索引 。这些索引直接定位经过解析的树中的存储节点(而不是文档) 。这种 XML 索引是 DB2 Viper 中引入的新概念 。 注意: 因为索引不与任何模式或映射相关联,如果模式改变了,那么可以定义新索引,而不必删除现有索引 。 | 为了了解迁移过程,先来看看在 DB2 Version 8.x 和 DB2 Viper 中创建能够存储 XML 数据的数据库的一些基本步骤 。
- 创建数据库并启用 XML 支持 。
DB2 Version 8.x
db2 create db MIGRATE dxxadm ENABLE_DB MIGRATE
| DB2 Viper
db2 create db MIGRATE using codeset utf-8 territory us
|
- 注册 DTD/XML 模式
DB2 Version 8.x 。只能注册 DTD 。
insert into db2xml.dtd_ref (dtdid, content, usage_count, author, creator, updator) values ( customerdtd, db2xml.XMLCLOBFromFile( /home2/hardeep/migrate/customer.dtd), 0, xml, xml, xml);
| DB2 Viper 。只能使用 XML 模式进行验证 。
db2 register xmlschema http://migrate.db2 from /home2/hardeep/migrate/customer.xsd as migrate.customer db2 complete xmlschema migrate.customer
|
- 创建表和存储 XML 数据的列
DB2 Version 8.x 。使用 XML Extender 数据类型 XMLCLOB 。
CREATE TABLE PurchaseOrder ( POid BIGINT NOT NULL PRIMARY KEY, Info DB2XML.XMLCLOB)
| 注意: 列的类型可以是 XMLCLOB、XMLVARCHAR 和 XML FILE 。 DB2 Viper 。XML 类型的列 。
CREATE TABLE PurchaseOrder ( POid BIGINT NOT NULL PRIMARY KEY, Info XML)
| 注意: 与 XMLCLOB、XMLVARCHAR 和 XML FILE 不同,XML 类型是一个标准的 SQL 类型 。
- 在 XML 数据上创建索引 。
DB2 Version 8.x 。创建 DAD 映射并启用 XML 列以便在副表上创建间接索引 。
dxxadm enable_column migrate purchaseorder info "/home2/hardeep/migrate/po.dad" -r poid
| DB2 Viper 。使用 xmlpattern 创建 XML 索引 。
create unique index order_key on purchaseorder (info) generate key using xmlpattern /purchaseOrder/@poid as sql double;
|
- 创建将输入的 XML 分解为关系数据的映射
DB2 Version 8.x 。创建 DAD 映射并启用 XML 集合 。
dxxadm enable_collection migrate customerinfo /home2/hardeep/migrate/customer.dad
| DB2 Viper 。对 XML 模式进行注释并启用它 。
db2 register xmlschema http://migrate.db2 from /home2/hardeep/migrate/customer.xsd as migrate.customer db2 complete xmlschema migrate.customer ENABLE DECOMPOSITION
|
将现有的 XML 数据库从 DB2 Version 8.x 迁移到 DB2 Viper 既然对数据库设置方式的差异有了一些理解,就来看看将现有的 XML 数据库从 DB2 Version 8.x 迁移到 DB2 Viper 所需的基本步骤 。 为 DB2 Viper 创建新的 UTF-8 数据库 首先需要理解的是,因为只支持对 XML 数据使用 UTF-8 编码,所以如果现有的数据库是非 UTF-8 的,那么需要用 UTF-8 编码页集创建一个新数据库 。 使用以下命令创建新数据库:
db2 create db migrate using codeset utf-8 territory us
| 接下来,需要将所有数据库对象从原数据库导出,然后将它们导入新数据库(UTF-8) 。这是一个手工操作 。本文只讨论与 XML 数据相关联的 DB2 对象的迁移过程,其余部分请参阅 DB2 迁移文档 。 本文提供了一个迁移实用程序 。它可以帮助您生成迁移数据库对象所需的一些数据定义语言(DDL)脚本 。 迁移 DTD 和 XML 模式 因为 DB2 Viper 不使用 DTD 进行 XML 验证,所以必须将当前 XML 应用程序使用的任何 DTD 转换为 XML 模式 。为此,首先需要将 DTD 从现有的 DB2 Version 8.x 数据库(DTD_REF 表)装载到本地文件系统中 。
select db2xml.XMLFileFromCLOB(db2xml.clob(content), /home2/hardeep/migrate/customer.dtd) from db2xml.dtd_ref where DTDID=customerdtd;
| 注意: 因为 XML 模式并不保存在数据库中,可以从文件系统获得它们 。 将 DTD 从 DTD_REF 表复制到文件系统之后,需要将它转换为 XML 模式 。有许多免费的基于 Web 的 XML 实用工具可以帮助您在 DTD 和 XML 模式之间进行转换(使用关键词 DTD Schema convert 进行搜索) 。 注册 XML 模式 为了使用 XML 模式验证 XML 文档,首先需要在 XML 模式存储库中注册它们 。
db2 register xmlschema http://migrate.db2 from /home2/hardeep/migrate/po.xsd as migrate.po db2 complete xmlschema migrate.po
| 注意:大型模式需要在应用程序堆中有足够的空间 。
db2 update db cfg using applheapsz 1000
| 将包含 XML 数据的表迁移到新数据库 在 DB2 Version 8.x 中,为了存储原样的 XML 文档,列的类型可以是 CLOB、BLOB、VARCHAR 或 XML Extender 类型 DB2XML.XMLCLOB、DB2XML.XMLVARCHAR 或 DB2XML.XMLFILE 。对于 DB2 Viper,列类型是 XML 。 因此,在 DB2 Version 8.x 中可以用下面的命令创建包含 CLOB 列的表来存储 XML 数据
CREATE TABLE Product(Pid VARCHAR(10) NOT NULL PRIMARY KEY, Name VARCHAR(128), Category VARCHAR(32),Price DECIMAL(30,2), Info CLOB);
| 而在 DB2 Viper 中应该创建 XML 列来存储 XML 数据:
CREATE TABLE Product(Pid VARCHAR(10) NOT NULL PRIMARY KEY, Name VARCHAR(128), Category VARCHAR(32), Price DECIMAL(30,2), Info XML);
| 注意: 在上面的表中,如果 NAME、CATEGORY 和 PRICE 列中的数据是从 XML 文档中提取的(为了创建关系索引),那么新表就根本不需要这些列,因为现在可以在存储的 XML 文档本身上创建索引 。这个表可以简化为两列 。
CREATE TABLE Product(Pid VARCHAR(10) NOT NULL PRIMARY KEY, Info XML);
| 在 DB2 Version 8.x 中创建的 DB2XML.XMLCLOB 列:
CREATE TABLE PurchaseOrder(Poid BIGINT NOT NULL PRIMARY KEY, Status VARCHAR(10) NOT NULL WITH DEFAULT New, Info DB2XML.XMLCLOB NOT LOGGED NOT COMPACT NOT NULL);
| 现在也成为 XML 列:
CREATE TABLE PurchaseOrder(Poid BIGINT NOT NULL PRIMARY KEY, Status VARCHAR(10) NOT NULL WITH DEFAULT New, Info XML NOT NULL);
| 将 XML 数据从 DB2 Version 8.x 迁移到 DB2 Viper 在新数据库中创建所有的表之后,下一步是将数据导出原数据库(DB2 Version 8.x)表并导入新数据库(DB2 Viper)表 。为了更好地理解这个过程,我们看看 DB2 Viper 的导入实用程序如何处理 XML 数据 。 DB2 IMPORT 实用程序提供了用来自 XML 文件的数据填充 XML 列的简便方法 。这个实用程序使用一个分界的 ASCII 文件,其中包含的一个参数指定需要导入的每个 XML 文件 。按照约定,这个文件的扩展名是 .DEL 。文件中的每一行代表要导入表中的一行数据 。如果一行包含 XML Data Specifier(XDS),那么 IMPORT 读取引用的 XML 文件中的数据并将其导入 DB2 。 从 DB2 Version 8.x 导出 XML 数据 因为 DB2 Version 8.x 的 EXPORT 实用程序不生成带 XDS 的 .DEL 文件,DB2 Viper 的 IMPORT 实用程序也可以处理 DB2 Version 8.x 的 EXPORT 实用程序为大对象(LOB)创建的 .DEL 文件 。 所以,对于 CLOB、BLOB、VARCHAR、DB2XML.XMLCLOB、DB2XML.XMLVARCHAR 或 DB2XML.XMLFILE 类型的列中存储的 XML 数据,第一步是使用 EXPORT 和 LOB 选项导出包含 XML 数据的表 。
EXPORT TO delfilename, OF DEL LOBS to lobfilespath MODIFIED BY LOBSINFILE select statement
| 注意: 如以下例子所示,lobfilespath 路径应该是存在的,delfilename 应该有完整的路径,这个路径也应该存在 。
DB2 EXPORT to C:/temp/migration/export/prod.del of del LOBS to C:/temp/migration/export/lobs modified by LOBSINFILE select pid,name,category,price,Info from product
| 注意: 在进行调用之前,路径 C:/temp/migration/export/lobs 应该已经存在 。 注意: 如果从新表中去掉了 name、category 和 price 列,那么应该修改 select 语句,只选择 pid 和 info 列 。 这个调用的输出生成一个 prod.del 文件和一个或多个包含 XML 数据的 lob 文件 。
100-100-01,Denim Roll Cuff Crop Pants,pants,+024.89,prod.del.001.lob.0.474/ 100-100-02,Bermuda Shorts,shorts,+09.99,prod.del.001.lob.474.488/
| 重点: 如果 XML 数据的列类型是 VARCHAR,那么需要在 select 语句中将这个列转换为 CLOB,以防止 XML 数据被放在 DEL 文件中 。
DB2 export to C:/temp/migration/export/prod.del of del LOBS to C:/temp/migration/export/lobs modified by LOBSINFILE select pid,name,category,price,cast(Info as clob) from product
| cast (Info as clob) 确保 XML 数据导出到 lob 文件,而不是添加到分界的(DEL)文件中 。 如果没有转换这个列,那么输出会像下面这样:
100-100-01,Denim ,pants,+024.89, 100-100-02,Bermuda ,shorts,+09.99,
| IMPORT 命令无法处理这种格式,因为它认为这是非良构的 XDS 。
将 XML 数据导入 DB2 Viper 现在可以使用 IMPORT 实用程序将导出的数据导入新数据库中创建的表中 。传递 DEL 文件的名称和 LOB 文件的路径 。
DB2 IMPORT FROM C:/temp/migration/export/prod.del OF DEL LOBS FROM C:/temp/migration/export/lobs MODIFIED BY XMLCHAR INSERT INTO product;
| 注意: 对于分解到关系列的 XML 数据,不需要迁移数据 。 迁移 XML 数据上的索引 在 DB2 Version 8.x 中,XML 列中存储的 XML 数据可以利用关系副表建立间接索引 。将副表中的值与 XML 列中的文档关联起来的映射信息在 DAD 文件中定义 。 由于 DB2 Viper 能够创建直接定位 XML 文档内部的路径的 XML 索引,所以不再需要使用副表来建立间接关系索引 。用来创建 XML 索引的一些关键参数与 DAD 映射中的参数相似 。可以使用 DAD 映射中这些参数的值来创建 XML 索引 。现在来分析一个 DAD 映射示例,这个 DAD 映射用来为 DB2XML.XMLCLOB 类型的 purchaseorder 列创建副表 。
path="/purchaseOrder/shipTo/name" multi_occurrence="NO"/>
| 这个映射中关键的参数是 //column/@path 和 //column/@type 。 在 DB2 Viper 中相应的 XML 索引是:
create index order_name on purchaseorder (info) generate key using xmlpattern /purchaseOrder/ shipTo/name as SQL VARCHAR(128);
| DAD 中的 //column/@path 值与 XML 索引中的 xmlpattern 相同,DAD 中的 //column/@type 值与 SQL 类型相同 。 另一个重要之处是根 ID,当用这个 DAD 文件在 DB2 Version 8.x 中启用 XML 列时,这个值传递给 enable_column 调用 。
dxxadm enable_column migrate purchaseorder info "/home2/hardeep/migrate/po.dad" -r poid
| 这个根 ID 标识出表中一个主键的名称,这个主键被添加到副表中,用来将副表与包含 XML 列的表关联起来 。根 ID 的值在 XML 列上是惟一的 。这个根 ID 对应于 XML 文档中的路径值,惟一地定义 XML 列中的这个文档 。 所以,当为 DB2 Viper 创建 XML 索引时,可以在 DB2 Version 8.x 中定义根 ID(主键)的路径上创建惟一索引(如果主键在 XML 文档中存在的话) 。
create unique index order_key on purchaseorder (info) generate key using xmlpattern /purchaseOrder/@poid as sql double;
| 迁移用来将 XML 数据分解为关系数据的映射文件 如果应用程序需要将输入的 XML 数据分解为关系表,而且您感觉这种需要仍然存在,那么需要将现有的 DAD 映射替换为带注释的 XML 模式映射 。 表 4. XML 集合和带注释的 XML 模式之间的差异
|
XML 集合 |
新的分解 |
映射文件 |
DAD |
带注释的模式 |
功能和性能 |
有限 |
功能得到了扩展,性能更好 |
DTD/模式 |
不需要 。可以注册,也可以不注册 。 |
需要 。必须注册 。 | 注意: 在这两种映射中,关系表都必须提前存在 。 因为关于 XML 文档和关系模式之间关系的映射信息存储在 DAD 文件中,可以利用这些 DAD 文件来了解 XML 模式所需的注释 。要想找到一种可以自动地将 DAD 文件转换为带注释的 XML 模式的工具,请参考 From DAD to annotated XML schema decomposition (developerWorks,2006 年 4 月) 。 对 XML 模式进行注释之后,可以在 XSR 中注册并启用它们 。
db2 register xmlschema http://migrate.db2 from /home2/hardeep/migrate/customer.xsd as migrate.customer db2 complete xmlschema migrate.customer ENABLE DECOMPOSITION
| 数据库迁移实用程序 本文提供了一个迁移实用程序的示例代码 。这个实用程序生成帮助进行数据迁移的脚本 。生成的脚本帮助执行以下步骤:
迁移命令 Migrate -p[path] -d[database] -s[schema] -t[able] -c[olumn] -[b[ackup]]
- path: 导出文件的目标目录 。
- database: 数据库的名称 。
- schema: 模式的名称 。
- table: 要迁移的表的名称 。
- column: 表中 XML 列的名称 。
- backup: 表是否需要在迁移之前备份到一个备份模式中 。
|
这个实用程序将脚本文件 migrate_script.db2 写到当前目录 。 编译 Java 代码 为编译 Java 代码,需要完成以下步骤:
- 创建目录 /temp/migrate 。
- 将 MigrateUtility_code.zip(可以在本文的 下载 一节中找到)复制到 temp 目录 。将 Migrate.java 和 XMLParse.java 解压到 /temp/samples 目录 。
- 编译 Java 文件 。
在 Microsoft Windows 上: 打开一个 db2 命令窗口 。
SET CLASSPATH= .;%DB2PATH%\java\db2java.zip; %DB2PATH%\java\db2jcc.jar;%DB2PATH%\java\db2jcc_license_cu.jar; "%DB2PATH%\java\jdk\bin\javac.exe" -d . *.java
| 在 AIX 上: 将 DB2PATH 设置为 DB2 SQLLIB 目录 。
CLASSPATH=$DB2PATH/java/sqlj.zip:$DB2PATH/java/db2java.zip $DB2PATH/java/jdk/bin/javac.exe" -d . *.java
| 注意: 以上命令假设采用 sh 或 bash shell 。对于 csh、tsh 和其他 shell,请做适当的修改 。
- 运行实用程序 。
"%DB2PATH%\java\jdk\jre\bin\java.exe" Migrate -p /temp/migrate d migrate -s hardeep -t purchaseorder -c info -b xmlextenderdata
|
下面是一个生成的脚本示例:
CONNECT TO MIGRATE; -- Scripts to backup data to schema- xmlextenderdata CREATE SCHEMA xmlextenderdata; CREATE TABLE "xmlextenderdata"."PURCHASEORDER"( "POID" BIGINT NOT NULL, "STATUS" VARCHAR(10) NOT NULL WITH DEFAULT New , "INFO" "DB2XML"."XMLCLOB" NOT LOGGED NOT COMPACT NOT NULL) IN "USERSPACE1"; DECLARE bcurs_purchaseorder CURSOR FOR SELECT * FROM hardeep.purchaseorder; LOAD FROM bcurs_purchaseorder OF cursor INSERT INTO xmlextenderdata.purchaseorder; -- Scripts to migrate data export to /temp/migrate purchaseorder/ purchaseorder.del of del lobs to /temp/migrate purchaseorder/lobs modified by LOBSINFILE SELECT * from purchaseorder; drop table purchaseorder; CREATE TABLE purchaseorder ( "POID" BIGINT NOT NULL , "STATUS" VARCHAR(10) NOT NULL WITH DEFAULT New , "INFO" XML NOT NULL ) IN "USERSPACE1"; import from /temp/migrate/purchaseorder/purchaseorder.del of del lobs from /temp/migrate/purchaseorder/lobs modified by XMLCHAR INSERT INTO purchaseorder; ALTER TABLE purchaseorder ADD PRIMARY KEY ("POID"); -- Scripts to restore data from backup schema- xmlextenderdata schema CONNECT TO MIGRATE; drop table purchaseorder; CREATE TABLE "HARDEEP "."PURCHASEORDER" ( "POID" BIGINT NOT NULL , "STATUS" VARCHAR(10) NOT NULL WITH DEFAULT New , "INFO" "DB2XML"."XMLCLOB" NOT LOGGED NOT COMPACT NOT NULL ) IN "USERSPACE1"; ALTER TABLE "HARDEEP "."PURCHASEORDER" ADD PRIMARY KEY ("POID"); DECLARE rcurs_purchaseorder CURSOR FOR SELECT * FROM xmlextenderdata.purchaseorder; LOAD FROM rcurs_purchaseorder OF cursor INSERT INTO hardeep.purchaseorder;
| 迁移 DB2 查询 DB2 Viper 可以混合使用 SQL/XML 和 XQuery 同时查询关系数据和 XML 数据 。 由于原来对 XML 文档进行分解的一些原因已经不存在了(比如使用关系列进行快速搜索),存储 XML 数据所需的关系模式可以大大简化 。因此,应用程序中处理 XML 数据的代码现在可以由 DB2 查询来替换,可以使用 SQL/XML 和 XQuery 在数据库服务器中提供同样的功能 。这对应用程序处理 XML 数据的方式的影响是非常惊人的:
- SQL 查询中嵌入的业务逻辑现在独立于应用程序环境 。另外,使用 SQL/XML 或 XQuery 编写的业务逻辑可以存储在视图或存储过程中,可供重用 。
- 中间层更简洁、更容易管理 。
- 数据库变成一个数据和服务提供者,从而简化了面向服务的体系结构(SOA) 。
- 数据在经过充分过滤之后才会离开数据库,这会减少数据库和应用程序之间的通信量 。
受影响的一些应用程序查询见 表 5: 表 5. 受影响的应用程序
|
DB2 UDB Version 8.x |
DB2 Viper |
插入 |
将 XML 文档存储到 DB2XML 列中的插入调用与存储 CLOB 的插入调用相似: insert into customer (info) values (?) 需要分解为关系表的 XML 文档使用 XML Extender 分解函数: dxxInsertXML,dxxShredXML |
插入调用仍然是一样的,除非文档需要进行验证 。XML 模式验证调用需要显式地添加到 insert 语句中 。 insert into customer (info) values (XMLValidate(?)) 需要分解为关系表的 XML 文档使用带注释的 XML 模式 decompose 函数或 SQL/XML XMLTABLE 函数 。 |
更新 |
对于原样存储的 XML 文档(比如 XMLClob 类型的列),可以使用 XML Extender UDF db2xml.update 进行子文档更新 。 这个 UDF 还同步更新对应的副表 。 |
对于原样存储的 XML 文档(比如 XML 类型的列),没有开箱即用的子文档更新函数 。 可以在本系列的第一篇文章 Partial updates to XML documents in DB2 Viper (developerWorks,2006 年 5 月)中找到一个用于子文档更新的 Java 存储过程 。 DB2XMLFUNCTIONS.XMLUPDATE |
查询 |
对于利用副表存储在 XML Extender 列中的 XML 文档,可以使用许多 XML Extender 提取函数来获得子文档数据 。 |
对于存储在 XML 列中的 XML 文档,可以使用 XQuery 查询 XML 文档的内部 。有许多支持 XQuery 的 SQL/XML 函数:
- XMLQUERY
- XMLEXISTS
- XMLTABLE
|
发布 |
原样存储的 XML 文档可以使用 XSLT UDF 进行转换,或者使用 XMLSERALIZE 或 XML2CLOB 进行串行化 。 可以使用 DAD 映射和 XML Extender 发布 UDF,或者使用 SQL/XML 发布函数将分解的 XML 数据发布为 XML 。 |
XML 列中原样存储的 XML 文档可以使用 XQuery 进行发布和转换,或者使用 XMLSERIALIZE 串行化成 SQL 字符串 。 对于分解的 XML 数据,需要在查询中使用 SQL/XML 发布函数 。 | 将 XML 数据插入 DB2 单一列中原样存储的 XML 如果 XML 数据原样存储在现有的应用程序中,那么对于处理 XML 数据插入的应用程序代码和 DB2 查询应该没有重大影响 。 DB2 Version 8.x 。将数据存储到 CLOB、VARCHAR、XMLCLOB 或 XMLVARCHAR 列中:
insert into customer (info) values (?)
| DB2 Viper 。XML 类型的列: 代码仍然是一样的,除非需要对数据进行解析或验证 。
insert into customer (info) values (?)
| 如果需要针对已注册的 XML 模式来验证数据,那么要将 XMLVALIDATE 添加到 insert 语句中 。
insert into customer (info) values (XMLValidate(?))
| 注意: 在 XML Extender 中,可以在副表的 DAD 映射中隐式地进行验证 。 如果需要修改 XML 文档的默认解析,那么可以在 insert 语句中使用 XMLPARSE 来指定解析选项 。
insert into customer (info) values (XMLPARSE(DOCUMENT cast(? as BLOB(2M)) preserve whitespace ))
| 注意: 原样存储的 XML 数据也可以分解并映射到关系表以便进行查询 。这可以使用 XML 列副表的 DAD 映射来实现,也可以在应用程序代码中实现 。因为在 DB2 Viper 中可以直接索引和搜索 XML 文档内部的节点,所以不必仅仅为了进行查询而将 XML 分解为关系数据 。处理分解的应用程序代码是多余的 。 分解到关系表的 XML 对于仍然需要分解的 XML 文档,处理数据插入和分解的查询和应用程序代码的变化很小 。 DB2 Version 8.x 。使用 XML Extender 分解函数 dxxInsertXML 和 dxxShredXML 进行 XML 文档分解 。
Call dxxShredXML (?, ?,?,? ); Call dxxInsertXML(customerdad, ?,?,? );
| DB2 Viper 。使用带注释的 XML 模式映射进行 XML 文‡档分解 。
Call xdbDecompXML (NULL,migrate.customer,?,?,1,NULL,NULL,NULL)
| 如果文档分解到单一表中,那么可以使用 XMLTABLE 进行分解 。
Insert into product(pid,info) select x.pid, X.doc from XMLTABLE ($info//product passing xmlparse( DOCUMENT cast(? as XML) ) AS "info" COLUMNS PID VARCHAR(12) PATH @pid, doc XML by ref PATH /) as x
| 如果在应用程序中使用 DOM 进行分解,那么不需要改变任何代码,除非希望将分解改为带注释的 XML 模式或使用 XMLTABLE 。 更新 DB2 中存储的 XML 文档 DB2 Version 8.x XML Extender 提供了一个 UDF,可以部分更新 DB2 中的 XML 文档 。Update 接受一个位置路径,指定要更新的元素或属性 。它返回与被更新列相似的数据类型 。XML 文档中与位置路径匹配的每个元素或属性的内容都更新为提供的值 。
Update purchaseorder set status=shipped, info=db2xml.update( info,/purchaseOrder/@status,shipped) where poid=2001;
| 因为 Update UDF 一次只处理一个位置路径,所以要想对文档进行大量修改,就需要将文档检索到客户机应用程序中,进行修改,然后使用 SQL update 语句将它插回数据库中 。 注意: XML Extender 列上的 update 触发器还更新对应的副表,从而保持 XML 列中的数据与副表中的数据同步 。 DB2 Viper 没有提供任何对数据库中的 XML 文档进行子元素更新的函数 。原因在于 XQuery 标准还没有定义更新的语法,但是已经有一些提案正在接受审议 。DB2 不希望在语言中引入只能短期使用的专用函数 。 对这个问题的解决方案是一个 Java 存储过程,这个过程可以在文章 Partial updates to XML documents in DB2 Viper (developerWorks,2006 年 5 月)中找到 。这个存储过程可以部分更新 DB2 中的 XML 文档 。更新存储过程还能够删除、替换和追加 XML 文档中的节点 。 注意: 在幕后,这个存储过程进行全文档更新 。
Call DB2XMLFUNCTIONS.XMLUPDATE ( path="/purchaseOrder/@status">shipped , Select info from purchaseorder where poid=2001, update purchaseorder set info=? where poid=2001,?,?);
| 注意: 因为也公布了源代码,所以既可以按原样使用这个存储过程,也可以模仿它编写自己的 Java 存储过程来操作 DB2 中的 XML 数据 。 查询并发布 DB2 中存储的 XML 文档 处理查询和发布的应用程序代码是受影响最大的代码之一 。对于 XML Extender 列中存储的 XML 数据,SQL 查询完全变了,因为它们涉及副表,而现在已经不再维护副表了 。 以下 SQL 查询两个表,返回有缩略图的产品的细节:
Select SQLPRODUCT.DETAILS, from SQLIMAGES,SQLPRODUCT where SQLPRODUCT.PID=SQLIMAGES.PID and SQLIMAGES.TYPE=thumbnail
| 这可以替换为针对一列的单一查询:
for $product in db2-fn:xmlcolumn("XMLPRODUCT.DESCRIPTION")/product where $product/description/images/image/@type="thumbnail" return $product/description/details/text()
|
提取并查询 XML 文档中的 XML 数据
DB2 XML Extender extract UDF 提供了许多从 XML 文档中提取数据的标量函数和表函数 。任何涉及使用 DB2 extract UDF 从 XML 文档中提取数据的 SQL 语句也必须替换为对 XMLEXIST、XMLQUERY 或 XMLTABLE 的等效调用 。
select db2xml.extractVarchar(info,/customerinfo/name) from xmlcustomer
|
可以替换为:
Select xmlcast( XMLQuery($cinfo/customerinfo/name passing info as "cinfo") as varchar(32)) from xmlcustomer
|
select info from customers where db2xml.extractvarchar(info,/customerinfo/name)=?
|
可以替换为:
select info from xmlcustomer where XMLExists( $cinfo/customerinfo[name=$name] passing info as "cinfo", cast(? as varchar(32)) as "name") |
DB2 XML Extender 提供了 ExtractCLOB () 和 ExtractCLOBs () UDF,用于提取 XML 文档的片段 。
select db2xml.extractclob(info,/customerinfo/addr) as RESULT from customer where cid = ?
|
可以替换为:
select x.add from xmlcustomer, XMLTABLE ($info//customerinfo passing info AS "info" COLUMNS add XML by ref PATH addr) as x where cid = ?
|
转换和发布 XML 数据
除了可以用来获得子文档信息的 extraction UDF 之外,DB2 XML Extender 还提供了用来转换数据库中的 XML 文档的 XSLT UDF 。
DB2 XML Extender 中定义的两个 XSL UDF 是 XSLTransformToClob() 和 XSLTransformToFile() 。
SELECT XSLTransformToClob( info, /temp/xslfilename.xsl) FROM xslcustomers SELECT XSLTransformToClob( info, ?) FROM xslcustomers Pass the XSL as a CLOB at runtime
|
尽管 DB2 Viper 的 XML Extender 支持提供了 XSL UDF,但是没有用于 XSL 转换的内置函数(这意味着,为了使用 XSLT UDF,需要启用数据库的 XML Extender 支持) 。因为,XQuery 在功能上与 XSL 有许多重复的地方,可以结合使用 XQuery 和 SQL/XML 函数来转换和发布 XML 文档 。
以下查询演示如何使用 XQuery 来查询和转换本机存储的 XML 文档 。这个 XQuery 构造称为 “customer” 的新元素,并向其中添加来自 XMLCUSTOMER 表中与条件(@country=United States)匹配的每个 XML 文档的 name、address 和 phone 节点 。然后,将这些 customer 元素返回到单一根节点 “customerlist” 中 。
图 7. 使用 XQuery 来查询和转换本机存储的 XML 文档
将关系数据转换并发布为 XML DB2 XML Extender DAD 文件和用于集合的存储过程提供了双向映射 。可以使用同样的映射进行分解和发布 。不幸的是,带注释的 XML 模式没有提供任何发布功能 。所以,进行发布的惟一方法是使用 SQL/XML 函数 。 考虑因素 本节包含在进行迁移时需要考虑到的一些因素 。这包括一些限制或最佳实践,可以帮助您在迁移 XML 应用程序时做出正确的决策 。全面的考虑因素列表请参见 DB2 Viper 的文档(Leveraging native XML support)和 ISV success with DB2 Viper: Prepare your applications, routines, and scripts for migration to DB2 Viper (developerWorks,2006 年 3 月) 。 对 XML 列的限制 下面是对 XML 列的限制:
- XML 列不能作为键列的一部分,包括主键、外键、惟一键、
多维聚簇(MDC)表的维键、范围聚簇表的序列键和分布或分区键 。 - XML 列不能作为任何索引的一部分,除非是 XML 数据上的索引 。
- XML 列不能具有由 WITH DEFAULT 子句指定的默认值;
如果这个列是可空的,那么默认值是 NULL 。 - XML 列不能用在物化查询表中 。
|
- XML 模式
下面是与 XML 模式相关的考虑因素:
- 大型模式需要在应用程序堆中有足够的空间 。建议扩大应用程序堆,如下所示:
db2 update db cfg using applheapsz 1000
|
- 因为没有 XML 模式与 XML 列相关联,所以从技术上说可以在单一列中插入来自不同模式的 XML 文档 。
索引 只有满足以下条件,才能将 XML 索引用于查询谓词:
- 索引包含查询谓词 。例如,如果索引的限制性等于或小于谓词 。这包括名称空间 。
- 查询谓词匹配索引数据类型 。
- 在谓词和索引定义中以一致的方式使用 /text() 。
尽可能使用完全指定的 XPath 。避免使用通配符(*、//),避免使用 /text() 。
/customerinfo/phone 而不是 //phone /customerinfo/addr/state 而不是 /customerinfo/*/state /customerinfo/name 而不是 /customerinfo/name/text() | 带注释的 XML 模式
- 注释不能用来验证实例文档 。
- 大多数 XML 模式成分都可以有注释 。
- 在进行分解时,只查看属于一个预定义名称空间的元素声明、属性声明和全局注释上的注释 。
- 涉及递归的 XML 模式不能用于分解 。它在注册时会失败 。
- 验证是可选的,可以用来添加默认值、修改文档或修改分解的结果 。
XMLPARSE 要避免的最大的问题是导致输入文档的编码不同于它的编码声明的编码页转换,或引入替换字符的编码页转换(如果目标编码页无法表示所有输入字符,就会出现这种情况) 。
- 强烈建议使用隐式的 XMLPARSE 。服务器期望接收 XML 类型,因此不进行任何编码页转换 。
insert into customer (cid, info) values (?,?)
|
- 使用显式的 XMLPARSE 会导致服务器期望接收字符或二进制类型(由 cast 子句决定) 。使用 XMLPARSE 并转换到 CLOB 会使文档的编码页转换为服务器上的数据库编码页 。这通常是不必要或不合适的 。
insert into customer (cid, info) values (?,XMLPARSE(DOCUMENT cast(? as CLOB(2M)) preserve whitespace ))
|
- 如果需要使用 XMLPARSE 来修改默认的解析选项,那么建议将数据转换为二进制类型而不是字符类型 。这会避免编码页转换问题 。因为以字节流形式读取输入的 XML 文件,所以在服务器上和 Java 端都不进行编码页转换 。转换到 BLOB 可以防止在服务器上转换文档的编码页 。
insert into customer (cid, info) values (?,XMLPARSE(DOCUMENT cast(? as BLOB(2M)) preserve whitespace ))
| XMLVALIDATE 下面是与 XMLVALIDATE 相关的考虑因素:
XMLQUERY 下面是与 XMLQUERY 相关的考虑因素:
- 在纯 XQuery 中不能绑定运行时谓词,但是可以通过 SQL/XML 函数或谓词(比如 XMLQUERY 、XMLTABLE 和 XMLEXISTS)间接地应用运行时谓词 。
- 对于 XQuery 比较,如果基类型是已知的,那么不进行隐式转换,不允许非法比较 。
XMLEXISTS 下面是与 XMLEXISTS 相关的考虑因素:
- 在 where 子句中使用 XMLEXISTS 而不是 XMLQUERY 。
- 只有在查询的结果是一个空序列时,XMLEXISTS 才会返回 false(这意味着 XMLEXISTS(false) 返回 true,因为这个查询的结果不是一个空序列) 。以下查询返回顾客表中的所有行,因为当 customerinfo/name 不是 Hardeep 时,查询返回一个包含 false 值的序列,而不是空序列 。
select c.info from xmlcustomer c where xmlexists( $i/customerinfo/name = "Hardeep" passing c.info as "i")
|
- 在 XMLEXISTS 谓词中使用方括号 [] 。如果将名称检查放在方括号中,那么前面的查询就会正常工作了,因为对于名称不是 Hardeep 的所有 customerinfo,查询现在返回空序列,XMLEXISTS 返回 false 。
select c.info from xmlcustomer c where xmlexists( $i/customerinfo[name = "Hardeep"] passing c.info as "i")
|
- 将多个 XML 谓词组合在一个 XMLEXISTS 中 。下面两个查询并不是一样的:
select * from customer where xmlexists( $c/customerinfo[name = Hardeep]) and xmlexists($c/customerinfo[phone = 555-555-555] .) select * from customer where xmlexists( $c/customerinfo[name=Hardeep and phone=555-555-555]...)
| 如果某个文档包含两个 customerinfo 元素,其中之一包含 name=hardeep 和 phone=111-111-111,另一个包含 name=Marja 和 phone=555-555-555,那么第一个查询返回这个文档,而第二个查询不返回它 。
(责任编辑:城尘 68476636-8003)
|