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语句

过程与函数的相同功能有:

  1. 都使用IN模式的参数传入数据、OUT模式的参数返回数据。
  2. 输入参数都可以接受默认值,都可以传值或传引导。
  3. 调用时的实际参数都可以使用位置表示法、名称表示法或组合方法。
  4. 都有声明部分、执行部分和异常处理部分。
  5. 其管理过程都有创建、编译、授权、删除、显示依赖关系等。

-- 包

1. 简介

包(PACKAGE)是一种数据对象,它是一组相关过程、函数、变量、常量和游标等PL/SQL程序设计元素的组合,作为一个完整的单元存储在数据库中,用名称来标识。

包类似于JAVA或C#语言中的类,包中的变量相当于类中的成员变量,过程和函数相当于类方法。

通过使用包,可以简化应用程序设计,提高应用性能,实现信息隐藏、子程序重载等面向对象语言所具有的功能。

与高级语言中的类相同,包中的程序元素也分为公用元素和私用元素两种,这两种元素的区别是他们允许访问的程序范围不同。公用元素不仅可以被包中的函数、过程所调用,也可以被包外的PL/SQL程序访问,而私有元素只能被包内的函数和过程序所访问。

一般是先编写独立的过程与函数,待其较为完善或经过充分验证无误后,再按逻辑相关性组织为程序包。

2. 包的优点

  1. 模块化:使用包,可以封装相关的类型、对象和子程序。把一个大的功能模块划分成多个小的功能模块,分别完成各自的功能,这样组织的程序易于编写,理解和管理。
  2. 更轻松的应用程序设计:包规范部分和包体部分可以分别创建并编译。换言之,我们可以在没有编写包体的情况下编写包规范的代码并进行编译。
  3. 信息隐藏:包中的元素可以分为公有元素和私有元素,公有元素可被程序包内的过程、函数等访问,还可以被包外的PL/SQL访问。但对于私有元素只能被包内的过程、函数等访问。对于用户,只需知道包规范,不用了解包体的具体细节。
  4. 性能更佳:应用程序第一次调用程序包中的某个元素时,就将整个程序包加载到内存中,当第二次访问程序包中的元素时,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子程序和包的更多相关文章

  1. 开发PL/SQL子程序和包及使用PL/SQL编写触发器、在JDBC中应用Oracle

    1.  子程序的各个部分: 声明部分.可执行部分.异常处理部分(可选) 2.子程序的分类: A.  过程 - 执行某些操作 a.  创建过程的语法: CREATE [OR REPLACE]  PROC ...

  2. 未安装Oracle数据库,使用PL\SQL Developer连接远程数据库解决方案

    使用PL/SQL远程连接Oracle服务器 背景:本地未安装oracle数据库服务器,希望远程连接Oracle服务器 1.下载oracle数据库客户端 下载64位windows的instantclie ...

  3. Oracle数据库编程:PL/SQL编程基础

    2.PL/SQL编程基础: PL/SQL块:        declare        定义部分        begin        执行部分        exception        异 ...

  4. Oracle 学习笔记 18 -- 存储函数和存储过程(PL/SQL子程序)

    PL/SQL子程序 它包含了函数和过程.此功能是指用户定义的函数.和系统功能是不同的.子程序通常完成特定的功能PL/SQL座.,能够被不同的应用程序多次调用.Oracle提供能够把PL/SQL程序存储 ...

  5. Oracle学习DaySix(PL/SQL续)

    一.游标 在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现.游标是一个指向上下文的句柄( handle)或指针.通过游标,PL/SQL 可以控制上下文区和处理语句时上 下文区会发生些 ...

  6. Oracle使用技巧及PL/SQL Developer配置

    Oracle使用技巧及PL/SQL Developer配置 摘自:http://livenzhao.spaces.live.com/blog/cns!6E368BE9F6DDD872!595.entr ...

  7. Oracle安装步骤及PL/SQL Developer连接数据库

    一:Oracle安装步骤及PL/SQL Developer连接数据库 win7 64位 11g 点击(操作步骤):http://www.cnblogs.com/haoke/articles/27343 ...

  8. Oracle instant client及pl sql developer的使用

    Oracle instant client的使用   最近重装了操作系统,使用的是Windows7 x64的版本,不准备安装Oracle,于是从官网上看到了Instant Client.   兴冲冲下 ...

  9. Oracle数据库使用Analyze提升sql性能

    Oracle数据库使用Analyze提升sql性能 如果你不使用analyze完成sql优化,将意味着:你拒绝使用数据库的查询优化器,也失去了使用优化连接的机会.假设你创建了一张拥有100万条记录的临 ...

随机推荐

  1. POJ 2417 Discrete Logging 离散对数

    链接:http://poj.org/problem?id=2417 题意: 思路:求离散对数,Baby Step Giant Step算法基本应用. 下面转载自:AekdyCoin [普通Baby S ...

  2. 国外代理server

    这里有几个国外的代理server 另外在网上能够找到很多这种 不能用的时候就在网上搜搜 稳定代理server 有非常多的 IP port 显示地址 24.245.58.130:32167 美国 新泽西 ...

  3. iOS8推送消息的回复处理速度

    iOS8我们有一个新的通知中心,我们有一个新的通报机制.当在屏幕的顶部仅需要接收一个推拉向下,你可以看到高速接口,天赋并不需要输入应用程序的操作.锁定屏幕,用于高速处理可以推动项目. 推送信息,再次提 ...

  4. group by和order by的错误

    select  u.Col_Name from hs_user u left join ( select tuid,count(*) as 'col_sumtopic' from BBS_Topic ...

  5. [LeetCode141]Linked List Cycle

    题目:Given a linked list, determine if it has a cycle in it. 判断一个链表是否有环 代码: /** * Definition for singl ...

  6. 【C语言探索之旅】 第一部分第七课:循环语句

    内容简介 1.课程大纲 2.第一部分第七课: 循环语句 3.第一部分第八课预告: 第一个C语言小游戏 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编 ...

  7. ZenCoding for EmEditor Snippets 的安装

    ZenCoding for EmEditor的安装 你可以从这里下载所需文件Library under the Snippets category.安装前请确认你的EmEditor内置有代码片段(Sn ...

  8. Oracle中merge into的使用 (转)

    该命令使用一条语句从一个或者多个数据源中完成对表的更新和插入数据. ORACLE 9i 中,使用此命令必须同时指定UPDATE 和INSERT 关键词,ORACLE 10g 做了如下改动. 1.ins ...

  9. Linux之父:除了写内核代码 别的真不会(转)

    Linus Torvalds 是 Linux 之父,被誉为活着的传奇. 其实很多人不了解他也并不奇怪,因为人是在是太低调了.现年 46 岁的他每天的工作仍然是编程,领导并推动着 Linux 的发展. ...

  10. 举例说,Linux核心名单(两)

    使用列表 我认为最好的方式,成为熟悉的核心列表功能是看一些简单的例子,素材去更好的理解链表. 以下是一个样例.包括创建.加入.删除和遍历链表. <span style="font-si ...