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語句 |
過程與函數的相同功能有:
- 都使用IN模式的參數傳入數據、OUT模式的參數返回數據。
- 輸入參數都可以接受默認值,都可以傳值或傳引導。
- 調用時的實際參數都可以使用位置表示法、名稱表示法或組合方法。
- 都有聲明部分、執行部分和異常處理部分。
- 其管理過程都有創建、編譯、授權、刪除、顯示依賴關系等。
-- 包
1. 簡介
包(PACKAGE)是一種數據對象,它是一組相關過程、函數、變量、常量和游標等PL/SQL程序設計元素的組合,作為一個完整的單元存儲在數據庫中,用名稱來標識。
包類似於JAVA或C#語言中的類,包中的變量相當於類中的成員變量,過程和函數相當於類方法。
通過使用包,可以簡化應用程序設計,提高應用性能,實現信息隱藏、子程序重載等面向對象語言所具有的功能。
與高級語言中的類相同,包中的程序元素也分為公用元素和私用元素兩種,這兩種元素的區別是他們允許訪問的程序范圍不同。公用元素不僅可以被包中的函數、過程所調用,也可以被包外的PL/SQL程序訪問,而私有元素只能被包內的函數和過程序所訪問。
一般是先編寫獨立的過程與函數,待其較為完善或經過充分驗證無誤后,再按邏輯相關性組織為程序包。
2. 包的優點
- 模塊化:使用包,可以封裝相關的類型、對象和子程序。把一個大的功能模塊划分成多個小的功能模塊,分別完成各自的功能,這樣組織的程序易於編寫,理解和管理。
- 更輕松的應用程序設計:包規范部分和包體部分可以分別創建並編譯。換言之,我們可以在沒有編寫包體的情況下編寫包規范的代碼並進行編譯。
- 信息隱藏:包中的元素可以分為公有元素和私有元素,公有元素可被程序包內的過程、函數等訪問,還可以被包外的PL/SQL訪問。但對於私有元素只能被包內的過程、函數等訪問。對於用戶,只需知道包規范,不用了解包體的具體細節。
- 性能更佳:應用程序第一次調用程序包中的某個元素時,就將整個程序包加載到內存中,當第二次訪問程序包中的元素時,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;