程序包的優點
模塊化:在程序包中可以包含過程函數、觸發器
更輕鬆的應用程序設計:
信息隱藏:把實現過程封裝在包中,使得訪問時無法看到實現過程
新增功能:定義公共的類型和變量,這是存儲過程和函數無法實現的
性能更佳:已經經過編譯,不需要每次都重複編譯
1、PL/SQL爲了滿足程序模塊化的需要,除了塊(block)和子程序結構外,還引入了包的構造。
2、程序包是對相關過程、函數、變量、遊標和異常等對象的封裝
3、程序包由規範和主體兩部分組成
程序包的定義和使用規範
包規範:
1、將相關對象存儲在一起的PL/SQL結構
2、包含二個分離的部件:包和包體
包的定義形式如下
包說明(公共的):
Package 包名 is
--變量說明;
--遊標說明;
--例外說明;
--記錄說明;
--Plsql表說明;
--過程說明;
--函數說明;
End[包名];
create or replace package ClassPackage as
procedure addStudent(p_studentid in student.studentid%type,
p_department in classes.department%type,
p_course in classes.course%type);--定義存儲過程
procedure removeStudent(p_studentid in student.studentid%type,
p_department in classes.department%type,
p_course in classes.course%type);--定義存儲過程
e_StudentNotRegistered exception;
type t_StudentIDTable is table of student.studentid%type
index by binary_integer;--定義類型
procedure ClassList(p_department in classes.department%type,
p_course in classes.course%type
p_IDs out t_StudentIDTable,
p_NumStudents in out binary_integer);--定義存儲過程
end ClassPackage;
包主體(私有的):
Package body 包名 is
--變量名說明;
--遊標說明;
--遊標申明;
--例外說明;
--記錄說明;
--plsql說明;
--過程體;
--函數體;
Begin
--語句序列
End [包名];
create or replace package body ClassPackage as
procedure addStudent(p_studentid in student.studentid%type,
p_department in classes.department%type,
p_course in classes.course%type) is
begin
insert into registered_students(student_id,department,course)
values(p_studentid,p_department,p_course);
commit;
end addStudent;
... ...(實現其他在包規範中定義的內容)
... ...(實現其他在包規範中定義的內容)
... ...(實現其他在包規範中定義的內容)
end ClassPackage
程序包用例1:(程序包的用法)
--定義包規範
create or replace package sales_report
as
cursor salescur return emp%rowtype;
end;
--包主體
create or replace package body sales_report
as
cursor salescur return emp%rowtype
is
select * from emp;
end;
調用:
SQL> declare ename emp%rowtype;
2 begin
3 open sales_report.salescur;
4 loop
5 fetch sales_report.salescur into ename;
6 exit when sales_report.salescur%notfound;
7 if ename.sal>3000 then
8 dbms_output.put_line(ename.ename||'你的工資還可以啊!');
9 elsif ename.sal<=3000 then
10 dbms_output.put_line(ename.ename||'你的工資有點低哦!');
11 end if;
12 end loop;
13 close sales_report.salescur;
14 end;
15 /
程序包用例2:(程序包的用法)
--定義包規範
create or replace package emp_data
as
type emprectype is record
(emp_id number(5),
emp_name varchar2(10),
job_title varchar2(9),
dept_name varchar2(14),
dept_loc varchar2(15));
--定義類型
type empcurtype is ref cursor return emprectype;
--定義存儲過程
procedure get_staff(dept_no in number,emp_cv in out empcurtype);
end;
--包主體
create or replace package body emp_data
as
procedure get_staff(dept_no in number,emp_cv in out empcurtype)
is
begin
open emp_cv for select empno,ename,job,dname,log from emp,dept
where emp.deptno = dept_no and emp.deptno = dept.deptno
order by emp.empno;
end;
end;
運行:
SQL> set autoprint on
SQL> var cv refcursor
SQL> exec emp_data.get_staff(20,:cv);
程序包定義規則
1、包部件可以是任意順序出現;
2、並非所有部件都必須被使用,所定義的變量不一定要被使用;
3、對函數/事件的聲明,必須是前向聲明。也就是說在包規範部分被聲明,包的主體才能被使用;
4、在編譯包主體時,先編譯包規範說明;
5、包主體也不是必須有的;
6、包內定義的函數/過程對外是可見的;
7、包內定義的函數/過程可以被重載。
程序包內函數/過程重載說明
1、兩個子程序的參數僅在名字或模式上是不同的,那麼不能重載
2、不能根據返回類型的不同來重載兩個函數
程序包的初始化
1、包第一次調用時被調入內存
2、可以添加初始化腳本來初始化包
Create or replace package body
Begin
Inital_code
End;
創建程序包
(1)程序包規範
Create [or replace]
Package
Package_name IS|AS
[Public item declarations]
[Subprogram specification]
End [package_name]
(2)程序包主體
Create [or replace]
Package body
Package_name is|as
[private item declarations]
[subprogram bodies]
Begin
[ initialization]
End [package_name]
程序包實例3:(創建程序包)
包的規範部分
Create or replace package pack_me
Is
Procedure order_proc(orno varchar2);
Function order_fun(ornos varchar2) return varchar2;
End pack_me;
包的主體部分
Create or replace package body pack_me as
Procedure order_proc(orno varchar2) is
Stat char(1);
Begin
Select ostatus into stat from order_master
Where orderno=orno;
......
End order_proc;
Function order_fun(ornos varchar2)
Return varchar2
Is
Icode varchar2(5);
Ocode varchar2(5);
Begin
......
End order_fun;
End pack_me;
程序包中的遊標
1、遊標的定義分爲遊標規範和遊標主體兩部分
2、在包規範中聲明遊標規範時必須使用RETURN字句指定遊標的返回類型
3、RETURN字句指定的數據類型可以是:用%ROWTYPE屬性引用表定義的記錄類型;程序員定義的記錄類型
程序包實例4:(程序包中的遊標)
包的規範部分
Create or replace package cur_pack is
Cursor ord_cur(vcode varchar2) return order_master%rowtype;
Pricedure ord_pro(vcode varchar2);
End cur_pack;
包的主體部分
Create or replace package body cur_pack as
Cursor ord_cur(vcode varchar2)
Return order_master%rowtype is
Select * from order_master where vencode=vcode;
Procedure ord_pro(vcode varchar2) is
Or_rec order_master%rowtype;
Begin
Open ord_cur(vcode);
Loop
Fetch ord_cur into or_rec;
Exit ehtn ord_cur%notfound
Dbms_output.put_line(‘返回值爲’||or_rec.orderno);
End loop;
End ord_pro;
End cur_pack;
程序包實例5:(程序包的使用)
包規範
create or replace package toyspack
is
procedure updatetoyprice;
function avgtoyprice return number;
end;
包主體
create or replace package body toyspack
is
procedure updatetoyprice
as
avgprice number;
begin
avgprice :=avgtoyprice;
while(avgprice<=400)
loop
update my_toys set price = case when price*1.1<500 then price*1.1
else price
end;
avgprice:=avgtoyprice;
end loop;
commit;
end;
function avgtoyprice
return number
as
avgprice number;
begin
select avg(price) into avgprice from my_toys;
return avgprice;
end;
end;
調用
SQL> set serveroutput on
SQL> select * from my_toys;
ID NAME PRICE
---------- --------------- ----------
P001 Doll 100
P002 Batman 125
P003 Spiderman 110
P004 He-man 200
SQL> execute toyspack.updatetoyprice;
PL/SQL procedure successfully completed
SQL> select * from my_toys;
ID NAME PRICE
---------- --------------- ----------
P001 Doll 345.227121
P002 Batman 431.533901
P003 Spiderman 379.749833
P004 He-man 471.589538
SQL> var avgnum number
SQL> execute :avgnum:=toyspack.avgtoyprice;
PL/SQL procedure successfully completed
avgnum
---------
407.025098755422
SQL> print avgnum;
avgnum
---------
407.025098755422
程序包實例6:(程序包的使用)
創建一個包:生成一個管理僱員工資的包sal_package,其中包括一個爲僱員的加薪過程和降薪過程
包規範
create or replace package sal_package
is
procedure raise_sal(v_empno emp.empno%type,v_sal_increment emp.sal%type);
procedure reduce_sal(v_empno emp.empno%type,v_sal_reduce emp.sal%type);
v_raise_sal emp.sal%type:=0;
v_reduce_sal emp.sal%type:=0;
end;
包主體
create or replace package body sal_package
is
procedure raise_sal(v_empno emp.empno%type,v_sal_increment emp.sal%type)
is
begin
update emp set sal=sal+v_sal_increment where empno = v_empno;
commit;
v_raise_sal:=v_raise_sal+v_sal_increment;
end;
procedure reduce_sal(v_empno emp.empno%type,v_sal_reduce emp.sal%type)
is
begin
update emp set sal=v_sal_reduce where empno = v_empno;
commit;
v_raise_sal:=v_raise_sal+v_sal_reduce;
end;
end;
調用
SQL> execute sal_package.raise_sal(7369,1000);
SQL> exec sal_package.reduce_sal(7369,1000);
子程序
命名的PL/SQL塊,編譯並存儲在數據庫中
子程序的各個部分:聲明部分、可執行部分、異常處理部分(可選)
子程序的分類:過程-執行某些操作;函數-執行操作並返回值
子程序的優點
1、模塊化:將程序分解爲邏輯模塊
2、可重用性:可以被任意數目的程序調用
3、可維護性:簡化維護操作
4、安全性:通過設置權限,是數據更安全
有關子程序和程序包的信息
User_objects視圖包含用戶創建的子程序和程序包信息
SQL> select object_name,object_type from user_objects where object_type in('PROCEDUAL','FUNCTION','PACKAGE');
User_source 視圖存儲子程序和程序包的源代碼
SQL> select line,text from user_source where name = 'SAL_PACKAGE';