Oracle數據庫之開發PL/SQL子程序和包


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語句

過程與函數的相同功能有:

  1. 都使用IN模式的參數傳入數據、OUT模式的參數返回數據。
  2. 輸入參數都可以接受默認值,都可以傳值或傳引導。
  3. 調用時的實際參數都可以使用位置表示法、名稱表示法或組合方法。
  4. 都有聲明部分、執行部分和異常處理部分。
  5. 其管理過程都有創建、編譯、授權、刪除、顯示依賴關系等。

-- 包

1. 簡介

包(PACKAGE)是一種數據對象,它是一組相關過程、函數、變量、常量和游標等PL/SQL程序設計元素的組合,作為一個完整的單元存儲在數據庫中,用名稱來標識。

包類似於JAVA或C#語言中的類,包中的變量相當於類中的成員變量,過程和函數相當於類方法。

通過使用包,可以簡化應用程序設計,提高應用性能,實現信息隱藏、子程序重載等面向對象語言所具有的功能。

與高級語言中的類相同,包中的程序元素也分為公用元素和私用元素兩種,這兩種元素的區別是他們允許訪問的程序范圍不同。公用元素不僅可以被包中的函數、過程所調用,也可以被包外的PL/SQL程序訪問,而私有元素只能被包內的函數和過程序所訪問。

一般是先編寫獨立的過程與函數,待其較為完善或經過充分驗證無誤后,再按邏輯相關性組織為程序包。

2. 包的優點

  1. 模塊化:使用包,可以封裝相關的類型、對象和子程序。把一個大的功能模塊划分成多個小的功能模塊,分別完成各自的功能,這樣組織的程序易於編寫,理解和管理。
  2. 更輕松的應用程序設計:包規范部分和包體部分可以分別創建並編譯。換言之,我們可以在沒有編寫包體的情況下編寫包規范的代碼並進行編譯。
  3. 信息隱藏:包中的元素可以分為公有元素和私有元素,公有元素可被程序包內的過程、函數等訪問,還可以被包外的PL/SQL訪問。但對於私有元素只能被包內的過程、函數等訪問。對於用戶,只需知道包規范,不用了解包體的具體細節。
  4. 性能更佳:應用程序第一次調用程序包中的某個元素時,就將整個程序包加載到內存中,當第二次訪問程序包中的元素時,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; 

 


免責聲明!

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



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