 | 级别: 初级 Maksym Petrenko, DB2 开源数据库技术人员, IBM Maria Schwenger, DB2 开源数据库技术人员, IBM
2009 年 10 月 12 日 IBM DB2® for Linux®, UNIX®, and Windows® 9.7 引入了对 PL/SQL 匿名块的支持:该特性让 PL/SQL 应用程序开发人员能够测试、诊断和原型化新的过程代码,模拟应用程序运行,以及动态地构建复杂的即席查询和报告。本文介绍了 DB2 9.7 中的匿名块,并通过常见的数据库场景展示了该特性的用途。
简介
本文为在以下场景在 DB2 9.7 中使用匿名块提供指导:
- 测试、诊断和开发新的 PL/SQL 存储过程
- 使用 PL/SQL 模拟应用程序运行
- 使用 PL/SQL 动态地 构建复杂的即席查询和报告
先决条件和系统需求
本文是为从 Oracle 迁移到 DB2 的 PL/SQL 应用程序开发人员和数据库管理员准备的。您应该理解 PL/SQL 过程语言。SQL PL 开发人员应该使用 DB2 原生复合 SQL 语句提供的对应函数。
为了使用本文提供的例子,您必须安装 DB2 9.7 Workgroup 或 Enterprise Edition for Linux, UNIX, and Windows。从 参考资料 部分可以下载 DB2 9.7 for Linux, UNIX, and Windows 的免费试用版。
使用例子
您可以使用各种工具运行本文的例子,包括 DB2 命令行处理器(CLP)、命令行实用程序(CLPPLUSU)或可视化工具(比如 Optim Development Studio)。如果您计划从 CLP 运行本文的例子,那么需要运行 SET SQLCOMPAT PLSQL 命令,以将新行上的前斜杠字符(/)识别为 PL/SQL 语句的终止字符。
为了在 DB2 中支持 PL/SQL 和 Oracle 数据类型,创建数据库时 DB2_COMPATIBILITY_VECTOR 注册表变量必须设置为 ORA,如清单 1 所示。
清单 1. 设置 DB2_COMPATIBILITY_VECTOR 注册表变量
db2set DB2_COMPATIBILITY_VECTOR=ORA
db2stop
db2start
db2 create db test
|
在您创建数据库之后,清单 2 提供的代码创建了一个简单的电子商务 PL/SQL 应用程序,用于管理在线订单。您还将用样例数据填充数据库的表。
清单 2. 示例代码
理解匿名块
匿名块是能够动态地创建和执行过程代码的 PL/SQL 结构,而不需要以持久化的方式将代码作为数据库对象储存在系统目录中。匿名块的概念类似于 UNIX shell 脚本,它支持将几个手动输入的命令合并到一个组,然后作为一个步骤执行。顾名思义,匿名块没有名称,因此不能从其他对象引用它们。尽管匿名块是动态地构建的,但可以轻松地将它们储存为操作系统文件中的脚本,以重复执行。
匿名块是标准的 PL/SQL 块。它们的语法和遵循的规则适用于所有 PL/SQL 块,包括声明、变量范围、执行、异常处理以及 SQL 和 PL/SQL 的使用。
匿名块的编译和执行被合并到一个步骤中,而 PL/SQL 存储过程的定义改变时,在使用它之前必须进行重新定义。这是匿名块与持久化命名数据库对象(比如存储过程和用户定义函数)相比的一个显著优势,因为它缩短了在代码中实现更改和实际执行之间的时间间隔。这个优点让匿名块在诊断问题、原型化和测试过程代码时发挥重要作用,因为这些任务通常需要多个更改-执行过程。
匿名块的另一个好处是它们不需要创建任何依赖项,在创建对象时也不需要任何特权,从而避免在生产环境中出现冲突。匿名块能够灵活地基于简单的选择特权运行任何操作序列,并且允许您在不创建或指向任何现有数据库对象的情况下进行测试。
可以从以下位置执行匿名块:
- SQL(例如,在 EXECUTE IMMEDIATE 语句中)
- DB2 API,比如 JDBC 和 ODBC
- 各种 DB2 工具,包括 CLP、CLPPlus、Optim Database Administrator 和 Optim Development Studio
使用匿名块原型化 PL/SQL 代码
在清单 3 中,应用程序开发人员希望实现一个机制来让业务需求与在 CUSTOMER 表中定义的客户进行通信(通过电子邮件)。为了满足需求,他决定编写一个简单的原型 PL/SQL 匿名块,以向 CUSTOMER 表中的客户发送包含消息的电子邮件。当业务需求最终实现之后,可以改进原型化匿名块并轻松将其转换成新的 PL/SQL 存储过程。注意,这个匿名块使用新的内置包,包括 UTL_SMTP(用于发送电子邮件的包)和 DBMS_OUTPUT(向标准输出写入消息的包),这两个包都是 DB2 9.7 的一部分。
清单 3. 一个简单的原型 PL/SQL 匿名块,它向 CUSTOMER 表中的客户发送包含消息的电子邮件
SET SERVEROUTPUT ON
/
DECLARE
conn UTL_SMTP.connection;
reply UTL_SMTP.reply;
msg VARCHAR2(1024);
sender VARCHAR2(255) DEFAULT 'demo\@ca.ibm.com';
recipients VARCHAR2(255);
subject VARCHAR2(255) DEFAULT 'Quick notification';
crlf VARCHAR2(2);
BEGIN
crlf := UTL_TCP.CRLF;
FOR row IN (SELECT first_name, email FROM customer) LOOP
DBMS_OUTPUT.PUT_LINE('Sending test email to customer ' || row.first_name || '...');
recipients := row.email;
msg := 'FROM: ' || sender || crlf ||
'TO: ' || recipients || crlf ||
'SUBJECT: ' || subject || crlf ||
crlf ||
'Hi ' || row.first_name || ', this is a test notification.';
UTL_SMTP.OPEN_CONNECTION('smtp_server.ibm.com', 25, conn, 10, reply );
UTL_SMTP.HELO(conn, 'localhost');
UTL_SMTP.MAIL(conn, sender);
UTL_SMTP.RCPT(conn, recipients);
UTL_SMTP.DATA(conn, msg);
UTL_SMTP.QUIT(conn);
END LOOP;
END;
/
Output:
Sending test email to customer Mike...
Sending test email to customer Joan...
Sending test email to customer Colin...
Sending test email to customer Graham...
Sending test email to customer Patsy...
|

 |

|
使用匿名块模拟应用程序运行
如前所述,匿名块的最常见用法就是调用过程语言对象,通常是为了进行测试。清单 4 显示了如何通过 PL/SQL 匿名块的帮助模拟应用程序的运行。清单 4 的代码在模拟应用程序运行的同时捕获性能度量指标。该匿名块模拟为来自现有 CUSTOMER 表的随机客户创建 10 个随机订单。它还输出测试的开始和终止时间,以及每次运行的订单细节。您可以轻松地将订单数改为从 10 到 20,然后重新运行这个匿名块而不需要再进行编译。您还可以为测试添加更多的性能度量指标。
清单 4. 在 PL/SQL 匿名块的帮助下模拟应用程序的运行
SET SERVEROUTPUT ON
/
DECLARE
v_customer_id customer.customer_id%TYPE;
product_id product.product_id%TYPE:=1;
o_order_id orders.order_id%TYPE;
v_test_start TIMESTAMP;
BEGIN
SELECT CURRENT TIMESTAMP INTO v_test_start FROM dual;
FOR k IN 1..10 LOOP
SELECT customer_id INTO v_customer_id FROM customer ORDER BY RAND() FETCH FIRST 1
ROW ONLY;
FOR i IN (
SELECT product_id, CAST(RAND()*50 as integer)+1 as quantity
FROM product
WHERE ROWNUM < CAST(RAND()*10 as integer))
LOOP
add_item_to_shopping_cart(i.product_id, i.quantity);
END LOOP;
create_order(v_customer_id, o_order_id);
DBMS_OUTPUT.PUT_LINE('--------------------------------------------');
END LOOP;
DBMS_OUTPUT.PUT_LINE('Test start: ' || v_test_start);
DBMS_OUTPUT.PUT_LINE('Test end : ' || CURRENT TIMESTAMP);
END;
/
Output:
Customer : Mike, Smith
Order creation : 07-06-2009
Estimated Delivery : 07-09-2009
Status : Shipped
Total price : $ 150,615.44
--------------------------------------------
Customer : Joan, Jett
Order creation : 07-06-2009
Estimated Delivery : 07-09-2009
Status : Shipped
Total price : $ 159,445.77
...
...
...
Customer : Colin, Taylor
Order creation : 07-06-2009
Estimated Delivery : 07-09-2009
Status : Shipped
Total price : $ 266,242.78
--------------------------------------------
Test start: 2009-07-06-11.10.11.500000
Test end : 2009-07-06-11.10.11.546000
|

 |

|
使用匿名块生成即席报告
一个常见的报告需求就是将数据从多个列合并到一个字符串中。这可以通过编写带有复杂递归的纯 SQL 语句来实现。不过,您可以使用带有动态格式化选项和简单逻辑流程的匿名块来更快地实现该目的。
清单 5 显示了如何在匿名块的帮助下创建一个即席报告。清单 5 的代码获取一个包含所有从商店订购产品的客户的列表,以及上个月的所有订单的总价值。在一行显示名称,名称之间用逗号分隔。
清单 5. 在匿名块的帮助下创建即席报告
SET SERVEROUTPUT ON
/
DECLARE
v_customer_names VARCHAR2(4000);
v_total_sales NUMBER(19,2);
BEGIN
DBMS_OUTPUT.PUT_LINE(' Last Month Sales Report ');
DBMS_OUTPUT.PUT_LINE('---------------------------------------');
DBMS_OUTPUT.PUT('Customer List: ');
FOR row IN
(SELECT distinct(a.customer_id),first_name, last_name FROM customer a, orders b
WHERE a.customer_id=b.order_id AND b.creation_time>CURRENT DATE -1 month)
LOOP
v_customer_names := v_customer_names || '"' || row.first_name || ' ' ||
row.last_name || '", ';
END LOOP;
IF(LENGTH(v_customer_names) > 0) THEN
v_customer_names := SUBSTR(v_customer_names,1, LENGTH(v_customer_names)-2);
ELSE
v_customer_names := 'None';
END IF;
DBMS_OUTPUT.PUT_LINE(v_customer_names);
SELECT NVL(SUM(total_price),0) INTO v_total_sales FROM orders WHERE creation_time>
CURRENT DATE - 1 month;
DBMS_OUTPUT.PUT_LINE('---------------------------------------');
DBMS_OUTPUT.PUT_LINE('Total Sales: ' || TO_CHAR(v_total_sales, '$99,999,999.99'));
END;
/
Output:
Last Month Sales Report ---------------------------------------
Customer List: "Mike Smith", "Joan Jett", "Colin Taylor", "Graham Norton", "Patsy Stone"
---------------------------------------
Total Sales: $ 49,772.56
|

 |

|
结束语
本文介绍了以下内容:
- 在 DB2 9.7 中引入的 PL/SQL 匿名块特性。
- 匿名块的概念。
- 匿名块如何为过程代码的测试、原型化和问题诊断提供便利。
- 匿名块如何模拟应用程序的运行。
- 如何使用匿名块实现强大的即席报告。
在 PL/SQL 匿名块的帮助下,您可以通过使用现有的 PL/SQL 脚本,或通过使用能够在其他数据库管理系统中工作的 PL/SQL 和 SQL 语句,在 DB2 环境中快速实现 PL/SQL 解决方案。
参考资料 学习
获得产品和技术
讨论
作者简介  | 
|  | Maksym Petrenko 是 IBM 多伦多实验室的 DB2 Beta Enablement Team 的成员。他帮助 DB2 的早期用户将他们的应用程序迁移到最新的 DB2 数据库中。Maksym 从 2001 年开始加入 IBM,担任过的职务包括开发人员、技术支持分析师和实验室服务顾问。他的经验包括为客户安装和配置应用程序提供支持、开发应用程序和解决 Windows、Linux 和 UNIX 平台上的 DB2 数据库性能问题。Maksym 是通过认证的 DB2 高级数据库管理员和 DB2 应用程序开发人员。 |
 | 
|  | Maria Schwenger 于 2005 年加入 IBM 的 Entity Analytic Solutions 团队,她在 Oracle 及 MS SQL Server 性能工程、数据库架构、管理及数据库开发方面拥有 10 多年经验,并且拥有从遗留数据库移植到关系数据库的丰富经验。目前,Maria 与早期版本的参与人员一起开发一个高接触(high-touch)模型以推动 DB2 Open Database Technology 的早期采用。 |
对本文的评价
|  |