Oracle 应用开发
实训指导书
第一章 PL/SQL 概述
为什么使用 PL/SQL?
一、PL/SQL 将 SQL 语言(4GL)的强大性和灵活性与 3GL 的过程性结构融为一体。
PL/SQL 是 Procedural Language/SQL 的缩写。正如其名字所示,PL/SQL 通过增加了用
在其它过程性语言中的结构对 SQL 进行了扩展,例如:
变量和类型(包括预定义和用户定义)。
控制结构,如-if-then-else 语句和循环。
过程和函数。
对象类型和方法。
过程性结构与 Oracle SQL 无缝地集成在一起,这便产生了一种结构化的强有力的语言。例
如,假设我们想修改一个学生纪录的主修课。如果这个学生不存在,我们就想创建一个新
纪录。那么,我们可以通过以下的 PL/SQL 代码实现这个目的:
DECLARE
/* Declare variables which will be used in SQL statements */
v_NewMajor VARCHAR2(10) := 'History';
v_FirstName VARCHAR2(10) := 'Scott';
v_LastName VARCHAR2(10) := 'Urman';
BEGIN
/* Update the students table. */
UPDATE students
SET major = v_NewMajor
WHERE first_name = v_FirstName
AND last_name = v_LastName;
/* Check to see if the record was found. If not, then we need
to insert this record. */
IF SQL%NOTFOUND THEN
INSERT INTO students (ID, first_name, last_name, major)
VALUES (student_sequence.NEXTVAL, v_FirstName, v_LastName,
v_NewMajor);
END IF;
END;
这个例子包括了两个不同的 SQL 语句(Update 和 Insert),这是 4GL 的结构,同时还有
3GL 的结构(变量声明和 IF 条件语句)。
PL/SQL 是独一无二的,它融合了灵活的 SQL 和强大的并可具有可配置性的 3GL。同时,
可以使用该语言集成的过程性结构和数据库访问接口。这些特性使该语言更加健壮和功能
强大,非常适合设计复杂的应用程序。
二、PL/SQL 和网络流量:
许多数据库应用程序的构建都使用客户机/服务器模型或者三层模型。在客户机/服务器中,
程序本身在客户机上,它将请求发往数据库服务器,等待所需的信息。这些请求使用 SQL
语言实现。通常,这样做会产生许多次网络传输交互,每个 SQL 语言都有单独的传输交互。
如果使用了 PL/SQL,几条 SQL 语句可被绑定在一个 PL/SQL 语句块中,作为一个单
独的单元发往服务器。这样做网络流量会减少,使应用程序执行得更快。
即使客户机服务器在同一台主机,这样也可以提高整个系统的性能,它减少了数据库对数
据库的调用次数。
PL/SQL 打包的优点同样适用于 B/S 三层模型结构。在这种情况下,客户机(通常运行
在 HTML 浏览器中)和应用程序服务器进行交互,而应用程序服务器随后将同数据库进行
交互。后一种交互充分体现了 PL/SQL 的优点。
PL/SQL 的功能特性:
一、
PL/SQL 的基本单元式语句块。所有的 PL/SQL 都是由语句块构成的,他们之间可以相互嵌
套。通常,每一语句块负责完成程序中某单元的工作,这样每一语句块就可以分担不同的
任务了。语句块拥有以下结构。
DECLARE
… /* Declare variables which will be used in SQL statements */
BEGIN
…
END;
只有可执行部分是必需的,声明部分和异常部分是可选的。可执行部分必须至少包括一条
可执行语句。语句块的不同部分将分派 DECLARE
/* Declare variables which will be used in SQL statements */
v_NewMajor VARCHAR2(10) := 'History';
v_FirstName VARCHAR2(10) := 'Scott';
v_LastName VARCHAR2(10) := 'Urman';
BEGIN
/* Update the students table. */
UPDATE students
SET major = v_NewMajor
WHERE first_name = v_FirstName
AND last_name = v_LastName;
/* Check to see if the record was found. If not, then we need
to insert this record. */
IF SQL%NOTFOUND THEN
INSERT INTO students (ID, first_name, last_name, major)
VALUES (student_sequence.NEXTVAL, v_FirstName, v_LastName,
v_NewMajor);
END IF;
END;
程序的不同处理功能。
二、错误处理
语句块的异常处理部分用于响应程序所遇到的运行时错误。通过将错误处理代码与程序主
体分离可以使程序本身的结构变得清晰。
例如,下面的 PL/SQL 语句块将进行这样的异常处理,它将错误发生的当前时间和遇到错
误的用户都纪录下来。
REM Error.sql
REM Chapter 1, Oracle9i PL/SQL Programming by Scott Urman
REM This block illustrates some of the error-handling features
REM of PL/SQL.
DECLARE
v_ErrorCode NUMBER; -- Code for the error
v_ErrorMsg VARCHAR2(200); -- Message text for the error
v_CurrentUser VARCHAR2(8); -- Current database user
v_Information VARCHAR2(100); -- Information about the error
BEGIN
/* Code that processes some data here */
EXCEPTION
WHEN OTHERS THEN
-- Assign values to the log variables, using built-in
-- functions.
v_ErrorCode := SQLCODE;
v_ErrorMsg := SQLERRM;
v_CurrentUser := USER;
v_Information := 'Error encountered on ' ||
TO_CHAR(SYSDATE) || ' by database user ' || v_CurrentUser;
-- Insert the log message into log_table.
INSERT INTO log_table (code, message, info)
VALUES (v_ErrorCode, v_ErrorMsg, v_Information);
END;
/
三、变量和类型
在 PL/SQL 和数据库之间是通过变量传递消息的。一个变量是一个存储单元,程序可读取
它,或给它赋值。在前面的例子,v_CurrentUser、v_ErrorCode 和 v_Information 都是变量。
变量是语句块的声明部分的。
每一个变量都有与之相关的明确类型。类型定义了该变量能够存储任何类型的信息。
PL/SQL 变量可以使数据拥有的类型:
Declare
v_StudentName VARCHAR2(20);
v_CurrentDate DATE;
v_NumberCredits NUMBER(3);
或者其它类型:
DECLARE
v_loopCounter BINARY_INTEGER;
v_CurrentlyRegistered BOOLEAN;
PL/SQL 也支持用户定义类型:表和纪录。用户定义类型允许用户制定自己程序中要处理的
数据结构。
DECLARE
TYPE t_StudentRecord IS RECORD(
FirstName VARCHAR2(10),
LastName VARCHAR2(10),
CurrentCredits NUMBER(3),
);
v_STUDENT t_studentRecord;
四、条件语句
PL/SQL 程序可根据测试结果有条件地执行代码的不同部分。这样的语句称为条件语句。
其主要结构就是 IF 语句。例如,下面的语句块将查询数据库以得到学生总数,并相应地向
tem_table 表中插入不同的信息:
REM Collections.sql
REM Chapter 1, Oracle9i PL/SQL Programming by Scott Urman
REM This block demonstrates some PL/SQL collections.
DECLARE
TYPE t_IndexBy IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
TYPE t_Nested IS TABLE OF NUMBER;
TYPE t_Varray IS VARRAY(10) OF NUMBER;
v_IndexBy t_IndexBy;
v_Nested t_Nested;
v_Varray t_Varray;
BEGIN
v_IndexBy(1) := 1;