Oracle Subprogram,即Oracle子程序,是Oracle数据库中存储的过程(Procedures)和函数(Functions)的统称。这些子程序是存储在数据库中的PL/SQL代码块,用于执行特定的任务或操作。下面详细介绍Oracle Subprogram的几个方面:
一、基本概念
- 过程(Procedures):过程是一系列为了完成特定功能而编写的SQL和PL/SQL语句的集合。过程执行操作但不返回值。
- 函数(Functions):函数也是一系列SQL和PL/SQL语句的集合,但它执行计算并返回一个值。
二、特点与优势
- 存储性:子程序存储在数据库中,可以在多个应用程序或数据库会话中重用,减少了代码冗余。
- 封装性:通过封装复杂的业务逻辑,子程序可以提高代码的可读性和可维护性。
- 安全性:通过控制对子程序的访问权限,可以保护数据库的安全。
三、类型
- 独立子程序:在模式级别创建,不依赖于其他包或对象。
- 包子程序:在包(Package)内创建,与包的其他部分(如类型、变量、游标等)紧密相关。
四、结构与组成
Oracle子程序遵循PL/SQL块结构,通常由以下几个部分组成:
- 声明部分(Declarative Part):包含子程序所需的类型、常量、变量、游标、异常等的声明。
- 执行部分(Executable Part):包含执行操作的SQL和PL/SQL语句。
- 异常处理部分(Exception Handling Part):包含处理执行过程中可能出现的异常的代码。
五、创建与调用
- 创建:使用
CREATE OR REPLACE PROCEDURE
(对于过程)或CREATE OR REPLACE FUNCTION
(对于函数)语句来创建子程序。 - 调用:在PL/SQL代码块、触发器、其他子程序或应用程序中,通过指定子程序的名称和必要的参数(如果有)来调用子程序。
六、示例
6.1 以下是一个简单的Oracle过程示例,用于向表中插入一行数据:
CREATE OR REPLACE PROCEDURE AddEmployee(
p_employee_id IN NUMBER,
p_employee_name IN VARCHAR2,
p_hire_date IN DATE
) AS
BEGIN
INSERT INTO employees (employee_id, employee_name, hire_date)
VALUES (p_employee_id, p_employee_name, p_hire_date);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE_APPLICATION_ERROR(-20001, 'An error occurred while inserting employee.');
END AddEmployee;
在这个示例中,AddEmployee
过程接受三个参数:员工ID(p_employee_id
)、员工姓名(p_employee_name
)和雇佣日期(p_hire_date
)。它执行一个INSERT语句将数据插入到employees
表中,并在成功插入后提交事务。如果在插入过程中发生任何异常,它将回滚事务并抛出一个应用程序错误。
6.2 声明、定义和调用简单的PL/SQL过程
Declaring, Defining, and Invoking a Simple PL/SQL Procedure
In this example, an anonymous block simultaneously declares and defines a procedure and invokes it three times. The third invocation raises the exception that the exception-handling part of the procedure handles.
DECLARE
first_name employees.first_name%TYPE;
last_name employees.last_name%TYPE;
email employees.email%TYPE;
employer VARCHAR2(8) := 'AcmeCorp';
-- Declare and define procedure
PROCEDURE create_email ( -- Subprogram heading begins
name1 VARCHAR2,
name2 VARCHAR2,
company VARCHAR2
) -- Subprogram heading ends
IS
-- Declarative part begins
error_message VARCHAR2(30) := 'Email address is too long.';
BEGIN -- Executable part begins
email := name1 || '.' || name2 || '@' || company;
EXCEPTION -- Exception-handling part begins
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE(error_message);
END create_email;
BEGIN
first_name := 'John';
last_name := 'Doe';
create_email(first_name, last_name, employer); -- invocation
DBMS_OUTPUT.PUT_LINE ('With first name first, email is: ' || email);
create_email(last_name, first_name, employer); -- invocation
DBMS_OUTPUT.PUT_LINE ('With last name first, email is: ' || email);
first_name := 'Elizabeth';
last_name := 'MacDonald';
create_email(first_name, last_name, employer); -- invocation
END;
/
Result:
With first name first, email is: John.Doe@AcmeCorp
With last name first, email is: Doe.John@AcmeCorp
Email address is too long.
PL/SQL procedure successfully completed.
6.3 声明、定义和调用简单的PL/SQL函数
Declaring, Defining, and Invoking a Simple PL/SQL Function
In this example, an anonymous block simultaneously declares and defines a function and invokes it.
DECLARE
-- Declare and define function
FUNCTION square (original NUMBER) -- parameter list
RETURN NUMBER -- RETURN clause
AS
-- Declarative part begins
original_squared NUMBER;
BEGIN -- Executable part begins
original_squared := original * original;
RETURN original_squared; -- RETURN statement
END;
BEGIN
DBMS_OUTPUT.PUT_LINE(square(100)); -- invocation
END;
/
-- Result
10000
PL/SQL procedure successfully completed.
6.4 函数中RETURN语句后恢复执行
Execution Resumes After RETURN Statement in Function
DECLARE
x INTEGER;
FUNCTION f (n INTEGER)
RETURN INTEGER
IS
BEGIN
RETURN (n*n);
END;
BEGIN
DBMS_OUTPUT.PUT_LINE (
'f returns ' || f(2) || '. Execution returns here (1).'
);
x := f(2);
DBMS_OUTPUT.PUT_LINE('Execution returns here (2).'|| f(x));
END;
/
-- Result
f returns 4. Execution returns here (1).
Execution returns here (2).16
PL/SQL procedure successfully completed.
6.5 每个执行路径都指向RETURN语句的函数
Function Where Every Execution Path Leads to RETURN Statement
CREATE OR REPLACE FUNCTION f (n INTEGER)
RETURN INTEGER
AUTHID DEFINER
IS
BEGIN
IF n = 0 THEN
RETURN 1;
ELSIF n = 1 THEN
RETURN n;
ELSE
RETURN n*n;
END IF;
END;
/
BEGIN
FOR i IN 0 .. 3 LOOP
DBMS_OUTPUT.PUT_LINE('f(' || i || ') = ' || f(i));
END LOOP;
END;
/
-- Result
f(0) = 1
f(1) = 1
f(2) = 4
f(3) = 9
PL/SQL procedure successfully completed.
6.6 程序中返回声明后恢复执行
Execution Resumes After RETURN Statement in Procedure
DECLARE
PROCEDURE p IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Inside p');
RETURN;
DBMS_OUTPUT.PUT_LINE('Unreachable statement.');
END;
BEGIN
p;
DBMS_OUTPUT.PUT_LINE('Control returns here.');
END;
/
-- Result
Inside p
Control returns here.
PL/SQL procedure successfully completed.
6.7 形式参数和实际参数
Formal Parameters and Actual Parameters
DECLARE
emp_num NUMBER(6) := 120;
bonus NUMBER(6) := 100;
merit NUMBER(4) := 50;
PROCEDURE raise_salary (
emp_id NUMBER, -- formal parameter
amount NUMBER -- formal parameter
) IS
BEGIN
UPDATE employees
SET salary = salary + amount -- reference to formal parameter
WHERE employee_id = emp_id; -- reference to formal parameter
END raise_salary;
BEGIN
raise_salary(emp_num, bonus); -- actual parameters
/* raise_salary runs this statement:
UPDATE employees
SET salary = salary + 100
WHERE employee_id = 120; */
raise_salary(emp_num, merit + bonus); -- actual parameters
/* raise_salary runs this statement:
UPDATE employees
SET salary = salary + 150
WHERE employee_id = 120; */
END;
/
6.8 实际参数和返回值仅继承子类型的范围
Actual Parameter and Return Value Inherit Only Range From Subtype
DECLARE
FUNCTION test (p INTEGER) RETURN INTEGER IS
BEGIN
DBMS_OUTPUT.PUT_LINE('p = ' || p);
RETURN p;
END test;
BEGIN
DBMS_OUTPUT.PUT_LINE('test(p) = ' || test(0.66));
END;
/
-- Result
p = .66
test(p) = .66
PL/SQL procedure successfully completed.
6.9 函数隐式地将形式参数转换为受约束的子类型
Function Implicitly Converts Formal Parameter to Constrained Subtype
DECLARE
FUNCTION test (p NUMBER) RETURN NUMBER IS
q INTEGER := p; -- Implicitly converts p to INTEGER
BEGIN
DBMS_OUTPUT.PUT_LINE('p = ' || q); -- Display q, not p
RETURN q; -- Return q, not p
END test;
BEGIN
DBMS_OUTPUT.PUT_LINE('test(p) = ' || test(0.66));
END;
/
-- Result
p = 1
test(p) = 1
PL/SQL procedure successfully completed.
七、总结
Oracle Subprogram是Oracle数据库中强大的编程结构,它们通过封装复杂的业务逻辑、提高代码重用性和维护性,在数据库应用程序开发中发挥着重要作用。