Oracle数据库之开发PL/SQL子程序和包
Oracle数据库之开发PL/SQL子程序和包
PL/SQL块分为匿名块与命名块,命名块又包含子程序、包和触发器。
过程和函数统称为PL/SQL子程序,我们可以将商业逻辑、企业规则写成过程或函数保存到数据库中,以便共享。
过程和函数均存储在数据库中,并通过参数与其调用者交换信息。过程和函数的唯一区别是函数总向调用者返回数据,而过程不返回数据。
1. 存储过程概念
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL语句集,存储在数据库中。经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。
2. 创建过程
语法:
- 1 CREATE [ OR REPLACE ] PROCEDURE [ schema. ] procedure_name
- 2 [ ( parameter_declaration [, parameter_declaration ]... ) ]
- 3 [ invoker_rights_clause ]
- 4 { IS | AS }
- 5 { [ declare_section ] body | call_spec | EXTERNAL} ;
说明:
procedure_name:过程名称。
parameter_declaration:参数声明,格式如下:
parameter_name [ [ IN ] datatype [ { := | DEFAULT } expression ]
| { OUT | IN OUT } [ NOCOPY ] datatype
IN:输入参数。
OUT:输出参数。
IN OUT:输入输出参数。
invoker_rights_clause:这个过程使用谁的权限运行,格式:
AUTHID { CURRENT_USER | DEFINER }
declare_section:声明部分。
body:过程块主体,执行部分。
一般只有在确认procedure_name过程是新过程或是要更新的过程时,才使用OR REPALCE关键字,否则容易删除有用的过程。
示例1:

- 1 CREATE PROCEDURE remove_emp (employee_id NUMBER) AS
- 2 tot_emps NUMBER;
- 3 BEGIN
- 4 DELETE FROM employees
- 5 WHERE employees.employee_id = remove_emp.employee_id;
- 6 tot_emps := tot_emps - 1;
- 7 END;

示例2:

- 1 CREATE OR REPLACE PROCEDURE insert_emp(
- 2 v_empno in employees.employee_id%TYPE,
- 3 v_firstname in employees.first_name%TYPE,
- 4 v_lastname in employees.last_name%TYPE,
- 5 v_deptno in employees.department_id%TYPE
- 6 )
- 7 AS
- 8 empno_remaining EXCEPTION;
- 9 PRAGMA EXCEPTION_INIT(empno_remaining, -1);
- 10 BEGIN
- 11 INSERT INTO EMPLOYEES(EMPLOYEE_ID, FIRST_NAME, LAST_NAME, HIRE_DATE,DEPARTMENT_ID)
- 12 VALUES(v_empno, v_firstname,v_lastname, sysdate, v_deptno);
- 13 DBMS_OUTPUT.PUT_LINE('插入成功!');
- 14 EXCEPTION
- 15 WHEN empno_remaining THEN
- 16 DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
- 17 DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
- 18 WHEN OTHERS THEN
- 19 DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
- 20 END;

3. 使用过程参数
当建立过程时,既可以指定过程参数,也可以不提供任何参数。
过程参数包括输入参数、输出参数和输入输出参数,其中输入参数(IN)用于接收调用环境的输入数据,输出参数(OUT)用于将输出数据传递到调用环境,而输入输出参数(IN OUT)不仅要接收输入数据,而且还要输出数据到调用环境。
3.1 带有输入参数的过程
通过使用输入参数,可以将应用程序数据传递到过程。当定义过程参数时,默认参数模式是输入参数,另外可以使用IN关键字显式定义输入参数。
示例:

- 1 CREATE OR REPLACE PROCEDURE insert_emp(
- 2 empno employee.empno%TYPE,
- 3 ename employee.ename%TYPE,
- 4 job employee.job%TYPE,
- 5 sal employee.sal%TYPE,
- 6 comm IN employee.comm%TYPE,
- 7 deptno IN employee.deptno%TYPE
- 8 )
- 9 IS
- 10 BEGIN
- 11 INSERT INTO employee VALUES(empno, ename, job, sal, comm, depno);
- 12 END;

3.2 带有输出参数的过程
通过在过程中使用输出参数,可以将数据或消息传递到调用环境和应用程序。当定义输出参数时,需要指定参数模式OUT。
示例:

- 1 CREATE OR REPLACE PROCEDURE update_sal(
- 2 eno NUMBER,
- 3 salary NUMBER,
- 4 name out VARCHAR2)
- 5 IS
- 6 BEGIN
- 7 UPDATE employee SET sal=salary WHERE empno=eno
- 8 RETURNING ename INTO name;
- 9 END;

3.3 带有输入输出参数的过程
通过在过程中使用输入输出参数,可以在调用过程时输入数据到过程,在调用结束后输出数据到调用环境和应用程序。当定义输入输出参数时,需要指定参数模式为IN OUT。
示例:

- 1 CREATE OR REPLACE PROCEDURE divide(
- 2 num1 IN OUT NUMBER,
- 3 num2 IN OUT NUMBER)
- 4 IS
- 5 v1 NUMBER;
- 6 v2 NUMBER;
- 7 BEGIN
- 8 v1 := trunc(num1 / num2);
- 9 v2 := mod(num1,num2);
- 10 num1 := v1;
- 11 num2 := v2;
- 12 END;

4. 调用过程
当在SQL*PLUS中调用过程时,需要使用CALL或者EXECUTE命令,而在PL/SQL块中过程可以直接引用。
ORACLE使用EXECUTE语句来调用存储过程语法:
1 EXEC[UTE] procedure_name(parameter1, parameter2, …);
示例:
- 1 -- 调用删除员工的过程
- 2 EXEC remove_emp(1);
- 3
- 4 -- 调用插入员工的过程
- 5 EXECUTE insert_emp(1, 'tommy', 'lin', 2);
示例:
- 1 DECLARE
- 2 v_name employee.ename%type;
- 3 BEGIN
- 4 update_sal(&eno,&salary,v_name);
- 5 dbms_output.put_line('姓名:'||v_name);
- 6 END;
5. 函数介绍
函数是一段独立的PL/SQL程序代码,它执行某个特定的、明确的任务。通常,函数将处理从程序的调用部分传递给它的信息,然后返回单个值。信息通过称为参数的特殊标识符传递给函数,然后通过RETURN语句返回。
6. 创建函数
语法:

- 1 CREATE [ OR REPLACE ] FUNCTION [ schema. ] function_name
- 2 [ ( parameter_declaration [, parameter_declaration]... )
- 3 ]
- 4 RETURN datatype
- 5 [ { invoker_rights_clause
- 6 | DETERMINISTIC
- 7 | parallel_enable_clause
- 8 | RESULT_CACHE [ relies_on_clause ]
- 9 }...
- 10 ]
- 11 { { AGGREGATE | PIPELINED } USING [ schema. ] implementation_type
- 12 | [ PIPELINED ] { IS | AS } { [ declare_section ] body
- 13 | call_spec
- 14 | EXTERNAL
- 15 }
- 16 } ;

示例:

- 1 CREATE FUNCTION get_bal(acc_no IN NUMBER)
- 2 RETURN NUMBER
- 3 IS
- 4 acc_bal NUMBER(11,2);
- 5 BEGIN
- 6 SELECT order_total INTO acc_bal FROM orders
- 7 WHERE customer_id = acc_no;
- 8 RETURN(acc_bal);
- 9 END;

函数参数也有输入、输出、输入输出三种模式:IN、OUT、IN OUT是形参的模式。若省略,则为IN模式。
和过程一样,IN模式的形参只能将实参传递给形参,进入函数内部,但只能读不能写,函数返回时实参的值不变。
OUT模式的形参会忽略调用时的实参值(或说该形参的初始值总是NULL),但在函数内部可以被读或写,函数返回时形参的值会赋予给实参。
IN OUT具有前两种模式的特性,即调用时,实参的值总是传递给形参,结束时,形参的值传递给实参。
调用时,对于IN模式的实参可以是常量或变量,但对于OUT和IN OUT模式的实参必须是变量。
示例:

- 1 CREATE OR REPLACE FUNCTION get_salary(
- 2 dept_no IN NUMBER DEFAULT 1,
- 3 emp_count OUT NUMBER)
- 4 RETURN NUMBER
- 5 IS
- 6 V_sum NUMBER;
- 7 BEGIN
- 8 SELECT SUM(SALARY), count(*) INTO V_sum, emp_count FROM EMPLOYEES
- 9 WHERE DEPARTMENT_ID=dept_no;
- 10 RETURN v_sum;
- 11 EXCEPTION
- 12 WHEN NO_DATA_FOUND THEN
- 13 DBMS_OUTPUT.PUT_LINE('数据不存在');
- 14 WHEN OTHERS THEN
- 15 DBMS_OUTPUT.PUT_LINE('其它异常:');
- 16 DBMS_OUTPUT.PUT_LINE('错误号:' || SQLCODE||',错误消息:'||SQLERRM);
- 17 END get_salary;

7 函数调用
语法:
- 1 function_name([[parameter_name1 =>] value1[, [parameter_name2 =>] value2, ...]]);
示例1:

- 1 DECLARE
- 2 v_num NUMBER;
- 3 v_sum NUMBER;
- 4 BEGIN
- 5 v_sum := get_salary(27, v_num);
- 6 DBMS_OUTPUT.PUT_LINE('部门27的工资总和:'||v_sum||',人数为:'||v_num);
- 7 END;

示例二:

- 1 DECLARE
- 2 v_num NUMBER;
- 3 v_sum NUMBER;
- 4 BEGIN
- 5 v_sum := get_salary(dept_no => 27, emp_count => v_num);
- 6 DBMS_OUTPUT.PUT_LINE('部门27的工资总和:'||v_sum||',人数为:'||v_num);
- 7 END;

示例3:

- 1 DECLARE
- 2 v_num NUMBER;
- 3 v_sum NUMBER;
- 4 BEGIN
- 5 v_sum := get_salary(emp_count => v_num);
- 6 DBMS_OUTPUT.PUT_LINE('部门27的工资总和:'||v_sum||',人数为:'||v_num);
- 7 END;

8. 删除过程或函数
删除过程语法:
DROP PROCEDURE [schema.]procudure_name;
删除函数语法:
DROP FUNCTION [schema.]function_name;
9. 过程与函数比较
过程 | 函数 |
---|---|
作为PL/SQL语句执行 | 作为表达式的一部分执行 |
在规范中不包含RETURN子句 | 必须在规范中包含RETURN子句 |
不返回任何值 | 必须返回单个值 |
可以RETURN语句,但是与函数不同,它不能用于返回值 | 必须包含至少一条RETURN语句 |
过程与函数的相同功能有:
- 都使用IN模式的参数传入数据、OUT模式的参数返回数据。
- 输入参数都可以接受默认值,都可以传值或传引导。
- 调用时的实际参数都可以使用位置表示法、名称表示法或组合方法。
- 都有声明部分、执行部分和异常处理部分。
- 其管理过程都有创建、编译、授权、删除、显示依赖关系等。
-- 包
1. 简介
包(PACKAGE)是一种数据对象,它是一组相关过程、函数、变量、常量和游标等PL/SQL程序设计元素的组合,作为一个完整的单元存储在数据库中,用名称来标识。
包类似于JAVA或C#语言中的类,包中的变量相当于类中的成员变量,过程和函数相当于类方法。
通过使用包,可以简化应用程序设计,提高应用性能,实现信息隐藏、子程序重载等面向对象语言所具有的功能。
与高级语言中的类相同,包中的程序元素也分为公用元素和私用元素两种,这两种元素的区别是他们允许访问的程序范围不同。公用元素不仅可以被包中的函数、过程所调用,也可以被包外的PL/SQL程序访问,而私有元素只能被包内的函数和过程序所访问。
一般是先编写独立的过程与函数,待其较为完善或经过充分验证无误后,再按逻辑相关性组织为程序包。
2. 包的优点
- 模块化:使用包,可以封装相关的类型、对象和子程序。把一个大的功能模块划分成多个小的功能模块,分别完成各自的功能,这样组织的程序易于编写,理解和管理。
- 更轻松的应用程序设计:包规范部分和包体部分可以分别创建并编译。换言之,我们可以在没有编写包体的情况下编写包规范的代码并进行编译。
- 信息隐藏:包中的元素可以分为公有元素和私有元素,公有元素可被程序包内的过程、函数等访问,还可以被包外的PL/SQL访问。但对于私有元素只能被包内的过程、函数等访问。对于用户,只需知道包规范,不用了解包体的具体细节。
- 性能更佳:应用程序第一次调用程序包中的某个元素时,就将整个程序包加载到内存中,当第二次访问程序包中的元素时,ORACLE将直接从内在中读取,而不需要进行磁盘I/O操作而影响速度,同时位于内存中的程序包可被同一会话期间的其它应用程序共享。因此,程序包增加了重用性并改善了多用户、多应用程序环境的效率。
3. 包的定义
PL/SQL中的包由包规范和包体两部分组成。建立包时,首先要建立包规范,然后再建立对包规范的实现–包体。
包规范用于声明包的公用组件,如变量、常量、自定义数据类型、异常、过程、函数、游标等。包规范中定义的公有组件不仅可以在包内使用,还可以由包外其他过程、函数使用。但需要说明与注意的是,为了实现信息的隐藏,建议不要将所有组件都放在包规范处声明,只应把公共组件放在包规范部分。
包体是包的具体实现细节,它实现在包规范中声明的所有公有过程、函数、游标等。也可以在包体中声明仅属于自己的私有过程、函数、游标等。
3.1 建立包规范
语法:
- 1 CREATE [ OR REPLACE ] [ EDITIONABLE | NONEDITIONABLE ]
- 2 PACKAGE [ schema. ] package_name
- 3 [ invoker_rights_clause ]
- 4 { IS | AS } item_list_1 END [ package_name ] ;
item_list_1:声明包的公用组件列表

- 1 { type_definition -- 数据类型
- 2 | cursor_declaration -- 游标
- 3 | item_declaration -- 变量、常量等
- 4 | function_declaration -- 函数
- 5 | procedure_declaration -- 过程
- 6 }
- 7 [ { type_definition
- 8 | cursor_declaration
- 9 | item_declaration
- 10 | function_declaration
- 11 | procedure_declaration
- 12 | pragma
- 13 }
- 14 ]...

示例:

- 1 CREATE OR REPLACE PACKAGE emp_mgmt AS
- 2 -- 函数
- 3 FUNCTION hire (last_name VARCHAR2, job_id VARCHAR2,
- 4 manager_id NUMBER, salary NUMBER,
- 5 commission_pct NUMBER, department_id NUMBER)
- 6 RETURN NUMBER;
- 7 FUNCTION create_dept(department_id NUMBER, location_id NUMBER)
- 8 RETURN NUMBER;
- 9 -- 过程
- 10 PROCEDURE remove_emp(employee_id NUMBER);
- 11 PROCEDURE remove_dept(department_id NUMBER);
- 12 PROCEDURE increase_sal(employee_id NUMBER, salary_incr NUMBER);
- 13 PROCEDURE increase_comm(employee_id NUMBER, comm_incr NUMBER);
- 14 -- 异常
- 15 no_comm EXCEPTION;
- 16 no_sal EXCEPTION;
- 17 END emp_mgmt;

3.2 建立包体
语法:
- 1 CREATE [ OR REPLACE ] PACKAGE BODY [ schema. ] package_name
- 2 { IS | AS }
- 3 BEGIN statement [ statement | pragma ]...
- 4 [ EXCEPTION exception_handler [ exception_handler ]... ]
- 5 [ initialize_section ]
- 6 END [ package_name ] ;
示例:

- 1 CREATE OR REPLACE PACKAGE BODY emp_mgmt AS
- 2 tot_emps NUMBER;
- 3 tot_depts NUMBER;
- 4 FUNCTION hire
- 5 (last_name VARCHAR2, job_id VARCHAR2,
- 6 manager_id NUMBER, salary NUMBER,
- 7 commission_pct NUMBER, department_id NUMBER)
- 8 RETURN NUMBER IS new_empno NUMBER;
- 9 BEGIN
- 10 SELECT employees_seq.NEXTVAL
- 11 INTO new_empno
- 12 FROM DUAL;
- 13 INSERT INTO employees
- 14 VALUES (new_empno, 'First', 'Last','first.example@example.com',
- 15 '(415)555-0100','18-JUN-02','IT_PROG',90000000,00,
- 16 100,110);
- 17 tot_emps := tot_emps + 1;
- 18 RETURN(new_empno);
- 19 END;
- 20 FUNCTION create_dept(department_id NUMBER, location_id NUMBER)
- 21 RETURN NUMBER IS
- 22 new_deptno NUMBER;
- 23 BEGIN
- 24 SELECT departments_seq.NEXTVAL
- 25 INTO new_deptno
- 26 FROM dual;
- 27 INSERT INTO departments
- 28 VALUES (new_deptno, 'department name', 100, 1700);
- 29 tot_depts := tot_depts + 1;
- 30 RETURN(new_deptno);
- 31 END;
- 32 PROCEDURE remove_emp (employee_id NUMBER) IS
- 33 BEGIN
- 34 DELETE FROM employees
- 35 WHERE employees.employee_id = remove_emp.employee_id;
- 36 tot_emps := tot_emps - 1;
- 37 END;
- 38 PROCEDURE remove_dept(department_id NUMBER) IS
- 39 BEGIN
- 40 DELETE FROM departments
- 41 WHERE departments.department_id = remove_dept.department_id;
- 42 tot_depts := tot_depts - 1;
- 43 SELECT COUNT(*) INTO tot_emps FROM employees;
- 44 END;
- 45 PROCEDURE increase_sal(employee_id NUMBER, salary_incr NUMBER) IS
- 46 curr_sal NUMBER;
- 47 BEGIN
- 48 SELECT salary INTO curr_sal FROM employees
- 49 WHERE employees.employee_id = increase_sal.employee_id;
- 50 IF curr_sal IS NULL
- 51 THEN RAISE no_sal;
- 52 ELSE
- 53 UPDATE employees
- 54 SET salary = salary + salary_incr
- 55 WHERE employee_id = employee_id;
- 56 END IF;
- 57 END;
- 58 PROCEDURE increase_comm(employee_id NUMBER, comm_incr NUMBER) IS
- 59 curr_comm NUMBER;
- 60 BEGIN
- 61 SELECT commission_pct
- 62 INTO curr_comm
- 63 FROM employees
- 64 WHERE employees.employee_id = increase_comm.employee_id;
- 65 IF curr_comm IS NULL
- 66 THEN RAISE no_comm;
- 67 ELSE
- 68 UPDATE employees
- 69 SET commission_pct = commission_pct + comm_incr;
- 70 END IF;
- 71 END;
- 72 END emp_mgmt;

4. 调用包的组件
包的名称是唯一的,但对于两个包中的公有组件的名称可以相同,用“包名.公有组件名“加以区分。
示例:

- 1 DECLARE
- 2 new_dno NUMBER; -- 部门编号
- 3 BEGIN
- 4 -- 调用emp_mgmt包的create_dept函数创建部门:
- 5 new_dno := emp_mgmt.create_dept(85, 100);
- 6 DBMS_OUTPUT.PUT_LINE('部门编号:' || new_dno);
- 7
- 8 -- 调用emp_mgmt包的increase_sal过程为员工加薪:
- 9 emp_mgmt.increase_sal(23, 800);
- 10 END;

5. 包中的游标
在包中使用无参游标,示例:

- 1 --定义包规范
- 2 CREATE OR REPLACE PACKAGE PKG_STU IS
- 3 CURSOR getStuInfo RETURN stuInfo%ROWTYPE;
- 4 END PKG_STU;
- 5
- 6 --定义包体
- 7 CREATE OR REPLACE PACKAGE BODY PKG_STU AS
- 8 CURSOR getStuInfo RETURN stuInfo%ROWTYPE IS
- 9 SELECT * FROM stuInfo;
- 10 END PKG_STU;
- 11
- 12 --调用包组件
- 13 BEGIN
- 14 FOR stu_Record IN PKG_STU.getStuInfo LOOP
- 15 DBMS_OUTPUT.PUT_LINE('学员姓名:'||stu_Record.name||',学号:'||stu_Record.id||',年龄:'||stu_Record.age);
- 16 END LOOP;
- 17 END;

在包中使用有参数的游标,示例:

- 1 --定义包规范
- 2 CREATE OR REPLACE PACKAGE PKG_STU IS
- 3 CURSOR getStuInfo(studentNo VARCHAR2) RETURN stuInfo%ROWTYPE;
- 4 END PKG_STU;
- 5
- 6 --定义包体
- 7 CREATE OR REPLACE PACKAGE BODY PKG_STU AS
- 8 CURSOR getStuInfo(studentNo VARCHAR2) RETURN stuInfo%ROWTYPE IS
- 9 SELECT * FROM stuInfo WHERE id=studentNo;
- 10 END PKG_STU;
- 11
- 12 --调用包组件
- 13 BEGIN
- 14 FOR stu_Record IN PKG_STU.getStuInfo(2) LOOP
- 15 DBMS_OUTPUT.PUT_LINE('学员姓名:'||stu_Record.name||',学号:'||stu_Record.id||',年龄:'||stu_Record.age);
- 16 END LOOP;
- 17 END;

由于游标变量是一个指针,其状态是不确定的,因此它不能随同包存储在数据库中,即不能在PL/SQL包中声明游标变量。但在包中可以创建游标变量参照类型,并可向包中的子程序传递游标变量参数。
示例:

- 1 -- 创建包规范
- 2 CREATE OR REPLACE PACKAGE CURROR_VARIBAL_PKG AS
- 3 TYPE dept_cur_type IS REF CURSOR RETURN dept%ROWTYPE; --强类型
- 4
- 5 TYPE cur_type IS REF CURSOR;-- 弱类型
- 6
- 7 PROCEDURE proc_open_dept_var(
- 8 dept_cur IN OUT dept_cur_type,
- 9 choice INTEGER DEFAULT 0,
- 10 dept_no NUMBER DEFAULT 50,
- 11 dept_name VARCHAR DEFAULT '%');
- 12 END;
- 13
- 14 -- 创建包体
- 15 CREATE OR REPLACE PACKAGE BODY CURROR_VARIBAL_PKG
- 16 AS
- 17 PROCEDURE proc_open_dept_var(
- 18 dept_cur IN OUT dept_cur_type,
- 19 choice INTEGER DEFAULT 0,
- 20 dept_no NUMBER DEFAULT 50,
- 21 dept_name VARCHAR DEFAULT '%')
- 22 IS
- 23 BEGIN
- 24 IF choice = 1 THEN
- 25 OPEN dept_cur FOR SELECT * FROM dept WHERE deptno = dept_no;
- 26 ELSIF choice = 2 THEN
- 27 OPEN dept_cur FOR SELECT * FROM dept WHERE dname LIKE dept_name;
- 28 ELSE
- 29 OPEN dept_cur FOR SELECT * FROM dept;
- 30 END IF;
- 31 END proc_open_dept_var;
- 32 END CURROR_VARIBAL_PKG;


- 1 定义一个过程,打开弱类型的游标变量:
- 2
- 3 --定义过程
- 4 CREATE OR REPLACE PROCEDURE proc_open_cur_type(
- 5 cur IN OUT CURROR_VARIBAL_PKG.cur_type,
- 6 first_cap_in_table_name CHAR)
- 7 AS
- 8 BEGIN
- 9 IF first_cap_in_table_name = 'D' THEN
- 10 OPEN cur FOR SELECT * FROM dept;
- 11 ELSE
- 12 OPEN cur FOR SELECT * FROM emp;
- 13 END IF;
- 14 END proc_open_cur_type;


- 1 测试包中游标变量类型的使用:
- 2
- 3 DECLARE
- 4 dept_rec Dept%ROWTYPE;
- 5 emp_rec Emp%ROWTYPE;
- 6 dept_cur CURROR_VARIBAL_PKG.dept_cur_type;
- 7 cur CURROR_VARIBAL_PKG.cur_type;
- 8 BEGIN
- 9 DBMS_OUTPUT.PUT_LINE('游标变量强类型:');
- 10 CURROR_VARIBAL_PKG.proc_open_dept_var(dept_cur, 1, 30);
- 11 FETCH dept_cur INTO dept_rec;
- 12 WHILE dept_cur%FOUND LOOP
- 13 DBMS_OUTPUT.PUT_LINE(dept_rec.deptno||':'||dept_rec.dname);
- 14 FETCH dept_cur INTO dept_rec;
- 15 END LOOP;
- 16 CLOSE dept_cur;
- 17
- 18 DBMS_OUTPUT.PUT_LINE('游标变量弱类型:');
- 19 CURROR_VARIBAL_PKG.proc_open_dept_var(cur, 2, dept_name => 'A%');
- 20 FETCH cur INTO dept_rec;
- 21 WHILE cur%FOUND LOOP
- 22 DBMS_OUTPUT.PUT_LINE(dept_rec.deptno||':'||dept_rec.dname);
- 23 FETCH cur INTO dept_rec;
- 24 END LOOP;
- 25
- 26 DBMS_OUTPUT.PUT_LINE('游标变量弱类型—dept表:');
- 27 proc_open_cur_type(cur, 'D');
- 28 FETCH cur INTO dept_rec;
- 29 WHILE cur%FOUND LOOP
- 30 DBMS_OUTPUT.PUT_LINE(dept_rec.deptno||':'||dept_rec.dname);
- 31 FETCH cur INTO dept_rec;
- 32 END LOOP;
- 33
- 34 DBMS_OUTPUT.PUT_LINE('游标变量弱类型—emp表:');
- 35 proc_open_cur_type(cur, 'E');
- 36 FETCH cur INTO emp_rec;
- 37 WHILE cur%FOUND LOOP
- 38 DBMS_OUTPUT.PUT_LINE(emp_rec.empno||':'||emp_rec.ename);
- 39 FETCH cur INTO emp_rec;
- 40 END LOOP;
- 41 CLOSE cur;
- 42 END;

6. 子程序重载
所谓重载时指两个或多个子程序有相同的名称,但拥有不同的参数变量、参数顺序或参数数据类型。
在调用重载子程序时,主程序将根据实际参数的类型和数目,自动确定调用哪个子程序。
PL/SQL允许对包内子程序和本地子程序进行重载。
示例:

- 1 -- 定义包规范
- 2 CREATE OR REPLACE PACKAGE PKG_EMP AS
- 3 FUNCTION get_salary(eno NUMBER) RETURN NUMBER;
- 4 FUNCTION get_salary(empname VARCHAR2) RETURN NUMBER;
- 5 END PKG_EMP;
- 6
- 7 -- 定义包体
- 8 CREATE OR REPLACE PACKAGE BODY PKG_EMP AS
- 9 FUNCTION get_salary(eno NUMBER) RETURN NUMBER
- 10 IS
- 11 v_salary NUMBER(10, 4);
- 12 BEGIN
- 13 SELECT sal INTO v_salary FROM emp WHERE empno=eno;
- 14 RETURN v_salary;
- 15 END;
- 16
- 17 FUNCTION get_salary(empname VARCHAR2) RETURN NUMBER
- 18 IS
- 19 v_salary NUMBER(10, 4);
- 20 BEGIN
- 21 SELECT sal INTO v_salary FROM emp WHERE ename=empname;
- 22 RETURN v_salary;
- 23 END;
- 24 END PKG_EMP;


- 1 测试:
- 2
- 3 DECLARE
- 4 v_sal NUMBER(10, 4);
- 5 BEGIN
- 6 v_sal := PKG_EMP.get_salary(7499);
- 7 DBMS_OUTPUT.PUT_LINE('工资:' || v_sal);
- 8 v_sal := PKG_EMP.get_salary('MARTIN');
- 9 DBMS_OUTPUT.PUT_LINE('工资:' || v_sal);
- 10 END;

Oracle数据库之开发PL/SQL子程序和包的更多相关文章
- 开发PL/SQL子程序和包及使用PL/SQL编写触发器、在JDBC中应用Oracle
1. 子程序的各个部分: 声明部分.可执行部分.异常处理部分(可选) 2.子程序的分类: A. 过程 - 执行某些操作 a. 创建过程的语法: CREATE [OR REPLACE] PROC ...
- 未安装Oracle数据库,使用PL\SQL Developer连接远程数据库解决方案
使用PL/SQL远程连接Oracle服务器 背景:本地未安装oracle数据库服务器,希望远程连接Oracle服务器 1.下载oracle数据库客户端 下载64位windows的instantclie ...
- Oracle数据库编程:PL/SQL编程基础
2.PL/SQL编程基础: PL/SQL块: declare 定义部分 begin 执行部分 exception 异 ...
- Oracle 学习笔记 18 -- 存储函数和存储过程(PL/SQL子程序)
PL/SQL子程序 它包含了函数和过程.此功能是指用户定义的函数.和系统功能是不同的.子程序通常完成特定的功能PL/SQL座.,能够被不同的应用程序多次调用.Oracle提供能够把PL/SQL程序存储 ...
- Oracle学习DaySix(PL/SQL续)
一.游标 在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现.游标是一个指向上下文的句柄( handle)或指针.通过游标,PL/SQL 可以控制上下文区和处理语句时上 下文区会发生些 ...
- Oracle使用技巧及PL/SQL Developer配置
Oracle使用技巧及PL/SQL Developer配置 摘自:http://livenzhao.spaces.live.com/blog/cns!6E368BE9F6DDD872!595.entr ...
- Oracle安装步骤及PL/SQL Developer连接数据库
一:Oracle安装步骤及PL/SQL Developer连接数据库 win7 64位 11g 点击(操作步骤):http://www.cnblogs.com/haoke/articles/27343 ...
- Oracle instant client及pl sql developer的使用
Oracle instant client的使用 最近重装了操作系统,使用的是Windows7 x64的版本,不准备安装Oracle,于是从官网上看到了Instant Client. 兴冲冲下 ...
- Oracle数据库使用Analyze提升sql性能
Oracle数据库使用Analyze提升sql性能 如果你不使用analyze完成sql优化,将意味着:你拒绝使用数据库的查询优化器,也失去了使用优化连接的机会.假设你创建了一张拥有100万条记录的临 ...
随机推荐
- ios-上拉电阻负载许多其他接口
想尝试拉加载意识到有多少开始了他的研究之旅,我看了两天做出最终的界面. 之所以这么慢是由于,我不知道要将上拉出现的view放在哪.就能在scrollView拉究竟部的时候被拉出来.还有就是怎么拉出来之 ...
- LoaderManager使用具体解释(二)---了解LoaderManager
了解LoaderManager 这篇文章将介绍LoaderManager类,这是该系列的第二篇文章. 一:Loaders之前世界 二:了解LoaderManager 三:实现Loaders 四:实例: ...
- pragma once与#ifndef的作用有什么区别
#pragma once 这是一个比较常用的指令,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次 #pragma once用来防止某个头文件被多次include,#ifndef,#defi ...
- 使用GDB在远程开发机上调试
由于一些环境限制,很多学生很可能需要在开发机器上调试.但是,由于对计算机资源的开发限制.在本地的直接机的发展GDB环境配置问题已经成为,其实,我们可以利用这段时间GDB自带gdbserver工具将能够 ...
- Velocity脚本新手教程
从网络下的数据汇编 一.Velocity简介 Velocity它是Apache该公司的开源产品,它是一套基于Java语言模板引擎,背景可以非常灵活的数据与模板文件一起反对.他直言不讳地说:,人使用模板 ...
- Microsoft Toolkit 2.5下载 – 一键激活Windows 8.1/2012 R2/Office 2013
http://www.dayanzai.me/microsoft-toolkit-2-5.html
- [three.js] 地图不能解决重复的问题 Solving with Texture RepeatWrapping Fail Issue
有些事情,如果你正在寻找侯,怎么也找不到. 有的东西,不经意间,到处: 我认为这是生活中常有的事. 然而,在互联网的浩瀚大海,这同样适用. 正常的一小会儿的积累, 投入少, 积累, 洋大海, 载起一帆 ...
- 学习vi和vim编辑(3):一个简单的文本编辑器(2)
然后文章,继续评论vi编辑简单的文本编辑命令. 本文主要是删除的文字.复制,运动命令. 删除文本: 正如上一篇文章中讲过的,对于删除命令("d")也具有"(command ...
- JAVA基础实例(三)--排序
冒泡排序 是一种简单的排序算法.它反复地走訪过要排序的数列,一次比較两个元素.假设他们的顺序错误就把他们交换过来.走訪数列的工作是反复地进行直到没有再须要交换,也就是说该数列已经排序完毕. 这个算法的 ...
- D3D 扎带 小样本
D3D 符合基本程序 #pragma once #pragma comment(lib,"d3d9.lib") #pragma comment(lib,"d3dx9.li ...