PL/SQL Package


Allow the Oralcel server to read multiple objects into memory at once.

Package bundle related PL/SQL types, items, and subprograms into one container.

包含2部分 : specification , body ( stored separately in the database )

The specification is the interface to your applications. ( 聲明 )

body : 真實定義

The package itself cannot be called . package once written and compiled, the contents can be shared by many applications.

When you call a packaged PL/SQL construct for the first time, the whole package is loaded into memory. ( thus, later calls to constructs in the same package require no disk input/output I/O )

Public package : are those that are declared in the package specification and defined in the package body.

Private package : are those that are defined solely within the package body.

image

變量可見度

image

G_VARIABLE_NAME ( g 前綴開頭的是 Global )

A package specification can exist without a package body, but a package body cannot exist without a package specification.

聲明: ( specification )

CREATE [ OR REPLACE ] PACKAGE package_name

IS | AS

  public type and item declarations

  subprogram specifications

END package_name;

例子 :

image

包體 ( body )

CREATE [ OR REPLACE ] PACKAGE BODY package_name

IS | AS

  private type and item declarations

  subprogram bodies

END package_name ;

It is quite common in the package body to see all private variables and subprograms defined first and the public subprograms defined last ( 先定義似有的, 再定義公共變量 )

例子 :

image

調用 :

EXECUTE comm_package.reset_comm( 0.15 )

EXECUTE scott.comm_package.reset_comm( 0.15 )   // different schema

EXECUTE comm_package.reset_comm@ny( 0.15 )     // remote database

可以只有 specification , 沒有 body.

刪除 :

DROP PACKAGE package_name ;

DROP PACKAGE BODY package_name;

包里的東西可以重載,比如 you can careate multiple subprograms with the same name in the same package, each taking parameters of different number or datatype.

重載例子 :

image

image

例如: 系統中的 TO_CHAR, 之類的,就是重載,可以接受不同參數。

You must declare an identifier before using it. Therefore, a subprogram must be declared before calling it.

( 必須先聲明,或者在 specification 中聲明,或者在 body中聲明,總之,真實定義之前必須要聲明 )

比如當系統在一個 procedure 中調用另一個 procedure , 但是,該 procedure 沒有被聲明或定義,那么它就不知道如何調用 ( 定義或聲明要在這個 procedure 之前 )

image

calc_rating(), 被調用了,但是 它的定義在下邊,所以就會出錯。

最好還是聲明,因為如果兩個 procedure 互相調用時,哪個放在前邊也是不行的。

image

包中,函數 Functions 的限制 : ( 跟之前單體函數的限制差不多 )

  • A function called from a query or DML statement may not end the current transaction , create or roll back to a savepoint, or alter the system or session
  • A function called from a query statement or from a parallelized DML statement may not execute a DML statement or otherwise modify the database
  • A function called from a DML statement may not read or modify the particular table being modified by that DML statement.

調用自己定義包中的函數

SELECT taxes_pack.tax( salary ) , salary, last_name FROM employees; // taxes_pack 包名

 

Oracle Supply package. ( 貌似只有少部分有用 )

Most of the standard packages are created by running catproc.sql

- 動態 ( 帶參數的 SQL ) ( 順序 : parse –> bind –> execute –> fetch )

   DBMS_SQL package 提供了 dynamic SQL .

   image

   例如 :

   image

   image

- DBMS_DDL package

- DBMS_JOB Subprograms

- DBMS_OUTPUT

   PUT, NEW_LINE, PUT_LINE, GET_LINE, GET_LINES, ENABLE/DISABLE

   image

 


1. 為什么使用包

答:在一個大型項目中,可能有很多模塊,而每個模塊又有自己的過程、函數等。而這些過程、函數默認是放在一起的(如在PL/SQL中,過程默認都是放在一起的,即Procedures中),這些非常不方便查詢和維護,甚至會發生誤刪除的事件。所以通過使用包就可以分類管理過程和函數。

有點類似 object – c

包分兩部分,包規范包體

2. 定義包說明
說明
3. 定義包體
包體
4. 使用包
使用

 


一、程序包的相關知識

1.定義與說明
a. 相關對象的封裝
b. 程序包的各部分
- 程序包規格說明
聲明子程序
- 程序包主體
定義子程序
2.使用程序包的優點
- 模塊化
- 更輕松的應用程序設計
- 信息隱藏
- 新增功能
- 性能更佳
3.公有項和私有項的區別
公有項:在程序包說明部分定義的變量、過程、函數
私有項:在程序包主體部分定義的變量、過程、函數
公有項 私有項
可以在程序包之外引用 不能在程序包之外引用
是在程序包規格說明中定義的 是在程序包主體中定義的
用於全局目的 用於局部目的

二、程序包創建說明

 

1.程序包規格說明
(1)、使用Create Package命令進行創建
(2)、包含公用對象和類型
(3)、聲明類型、常量、變量、異常、游標和子程序
(4)、可以在沒有程序包主題的情況下存在
(5)、可以重載
- 程序包中的多個子程序可以具有相同的名稱
- 它們的形參是不同的
- 只能位於打包的子程序中
- 限制
a. 如果子程序的參數僅名稱或模式不同,則不能重載
b. 不能基於其返回類型重載子程序
2.程序包主體
(1)、使用Create Package body 命令進行創建
(2)、包含子程序和游標的定義
(3)、包含私有聲明
(4)、不能在沒有程序包規格說明的情況下獨立存在
3.程序包的調用
包名.類型名;
包名.函數名[參數表];
包名..過程名[參數表];
(1)、 Package-name.type-name
(2)、 Package-name.object-name
(3)、 Package-name.subprogram-name
其中,Package-name 是程序包名稱,type-name是類型名稱,
object-name是對象名稱,subprogram-name 是子程序名稱
--示例
DBMS_output.put_line(Hello);
(4)、對於返回參數是游標類型的調用(如:引用游標)
set autoprint on --打開Sqlplus輸出
variable tempCur RefCursor; --定義一個宿主類型的引用游標變量
exec StudentPackage.ReturnStudent(:tempCur); --執行帶有引用游標的過程 注意使用宿主類型的變量前面要加“:”符號
4. 有關子程序和程序包的信息
A.數據字典
User_objects 用於檢查對象是否存在
User_source 用於獲取對象的代碼
B. 包的修改和刪除
Alter Package [Body] 包名
Alter Package Body StudentPackage;
Drop Package [Body] 包名
Drop Package Body StudentPackage;
5. 創建格式
A.創建包規格部分
格式:Create [or replace] Package 包名
IS|AS
變量聲明;
類型定義;
異常聲明;
游標聲明;
函數說明;
過程說明;
Pragma restrict_references(過程名或函數名,WNDS[,WNPS][,RNDS][,RNPS]) --編譯指令 限定函數的操作
End [包名];
B.創建包主體部分
格式: Create [or replace] package body 包主體名 --包主體名一定要是已經定義的包名
IS|AS
變量聲明; --具體的實現部分
類型定義;
異常聲明;
游標聲明;
函數說明;
過程定義;
End [包主體名];

6. 示例
示例1.創建程序包的規格說明部分  

--1
 1 Create or replace Package StudentPackage 
 2 is 
 3 Type curRefStudent is Ref Cursor Return Student%rowtype; 
 4 Procedure SelectStudent(FindID in Student.stuid%type); 
 5 Procedure InsertStudent(NewStudent in Student%rowType); 
 6 Procedure UpdateStudent(NewStudent in Student%rowType); 
 7 Procedure DeleteStudent(DelID in Student.stuid%type); 
 8 Procedure ReturnStudent(inOutstu in out curRefStudent); 
 9 Function RegurnRecordCount Return Number; 
10 End studentPackage; 


示例2.創建程序包的主體部分  

--2
 1 Create or replace Package Body StudentPackage IS 
 2 Procedure SelectStudent (FindID in Student.stuid%type) as --注意沒有Create 
 3 /*實現查詢過程的定義*/ 
 4 Cursor findCur is select * from student where stuid=FindID; 
 5 Begin 
 6 For S in FindCur Loop 
 7 DBMS_output.put_line(S.stuID||' '||s.StuName||' '||S.Sex); 
 8 End Loop; 
 9 Exception 
10 When No_Data_Found Then 
11 DBMS_output.Put_Line('沒有查到ID為'||FindID||'的記錄!'); 
12 When Others Then 
13 DBMS_output.Put_Line('查詢過程中發生意外情況'); 
14 End SelectStudent; --結束查詢過程 
15 /*實現插入過程的定義*/ 
16 Procedure InsertStudent(NewStudent in Student%rowType) as 
17 iRec Integer; 
18 Not_Exists_Student Exception; --預定義異常 
19 Begin 
20 Select count(*) into iRec from student where stuid=NewStudent.stuID; 
21 IF iRec>0 Then 
22 Raise Not_Exists_Student; 
23 Else 
24 insert into student values(NewStudent.stuid,NewStudent.stuName,NewStudent.sex); 
25 commit; 
26 End IF; 
27 Exception 
28 When Not_Exists_Student Then 
29 DBMS_output.Put_Line('要插入的編號:'||NewStudent.stuid||'的記錄已經存在'); 
30 When Others Then 
31 DBMS_output.Put_Line('插入記錄操作過程中出現錯誤'); 
32 End InsertStudent;--結束插入過程 
33 /*實現更新過程的定義*/ 
34 Procedure UpdateStudent(NewStudent in Student%rowType) as 
35 iRec Integer; 
36 Begin 
37 select Count(*) into iRec From student Where stuid=NewStudent.stuid; 
38 IF iRec =0 Then 
39 DBMS_output.Put_Line('編號為:'||NewStudent.stuid||'的記錄不存在,修改失敗'); 
40 ELSE 
41 Update student Set Stuname=NewStudent.stuName,Sex=NewStudent.Sex 
42 WHERE stuid=NewStudent.stuID; 
43 Commit; 
44 End IF; 
45 Exception 
46 When No_Data_Found Then 
47 DBMS_output.Put_Line('編號為:'||NewStudent.stuID||'的記錄不存在,修改失敗'); 
48 When Others Then 
49 DBMS_output.Put_Line('執行修改操作時發生意外情況,修改未成功'); 
50 End UpdateStudent;--結束修改過程 
51 /*實現刪除過程的定義*/ 
52 Procedure DeleteStudent(DelID in Student.stuid%type) as 
53 iRec Integer; 
54 Begin 
55 Select Count(*) into iRec From Student Where stuID=DelID; 
56 IF iRec=0 Then 
57 DBMS_output.Put_Line('編號為:'||DelID||'的記錄不存在,刪除操作時未成功'); 
58 ELSE 
59 Delete From student Where stuid=DelID; 
60 Commit; 
61 DBMS_output.Put_Line('刪除成功!'); 
62 End IF; 
63 Exception 
64 When Others Then 
65 DBMS_output.Put_Line('執行刪除操作時發生意外情況,刪除未成功'); 
66 End DeleteStudent; 
67 /*實現參數帶有游標類型定義*/ 
68 Procedure ReturnStudent(inOutstu in out curRefStudent) as 
69 Begin 
70 Open inOutstu For Select * from student; 
71 End ReturnStudent; 
72 /*實現函數定義*/ 
73 Function RegurnRecordCount Return Number as 
74 RecCount number(10); 
75 Begin 
76 Select Count(*) into RecCount From student; 
77 Return recCount; 
78 Exception 
79 When Others Then 
80 DBMS_output.Put_Line('查詢表中記錄數時發生意外情況'); 
81 End RegurnRecordCount; --結束函數的定義 
82 End studentPackage;--結束包 


示例3:調用包
1. 調用studentPackage包中的InsertStudent過程  

--invoke1
1 Declare 
2 newStu Student%RowType; 
3 Begin 
4 newStu.stuID:='1001'; 
5 newStu.stuName:='張三'; 
6 newStu.sex:=''; 
7 studentPackage.InsertStudent(newStu); 
8 End; 
9 / 


2. 調用studentPackage包中的UpdateStudent過程  

--invoke2
 1 Declare 
 2 newStu Student%RowType; 
 3 Begin 
 4 newStu.stuID:='1001'; 
 5 newStu.stuName:='李四'; 
 6 newStu.sex:=''; 
 7 studentPackage.UpdateStudent(newStu); 
 8 Exception 
 9 When Dup_Val_On_Index Then 
10 DBMS_output.Put_Line('唯一約束被破壞'); 
11 When Others Then 
12 DBMS_output.Put_Line('更新過程出現錯誤'); 
13 End; 
14 / 


3. 調用studentPackage包中的DeleteStudent過程  

--invoke3
1 Begin 
2 studentPackage.DeleteStudent('1001'); 
3 End; 
4 / 


4. 調用studentPackage包中的ReturnRecordCount函數  

--invoke4
1 Begin 
2 DBMS_output.put_Line(studentPackage.ReturnRecordCount); 
3 End; 
4 / 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM