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.
變量可見度
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;
例子 :
包體 ( 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 ( 先定義似有的, 再定義公共變量 )
例子 :
調用 :
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.
重載例子 :
例如: 系統中的 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 之前 )
calc_rating(), 被調用了,但是 它的定義在下邊,所以就會出錯。
最好還是聲明,因為如果兩個 procedure 互相調用時,哪個放在前邊也是不行的。
包中,函數 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 .
例如 :
- DBMS_DDL package
- DBMS_JOB Subprograms
- DBMS_OUTPUT
PUT, NEW_LINE, PUT_LINE, GET_LINE, GET_LINES, ENABLE/DISABLE
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 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.創建程序包的主體部分

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過程

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過程

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過程

1 Begin 2 studentPackage.DeleteStudent('1001'); 3 End; 4 /
4. 調用studentPackage包中的ReturnRecordCount函數

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