包和子程序

程序包的優點

模塊化:在程序包中可以包含過程函數、觸發器

更輕鬆的應用程序設計:

信息隱藏:把實現過程封裝在包中,使得訪問時無法看到實現過程

新增功能:定義公共的類型和變量,這是存儲過程和函數無法實現的

性能更佳:已經經過編譯,不需要每次都重複編譯

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';

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章