oracle 建立,刪除存儲過程,參數傳遞,建立,刪除存儲函數,存儲過程和函數的查看,包,系統包

認識存儲過程和函數  
存儲過程和函數也是一種PL/SQL塊,是存入數據庫的PL/SQL塊。但存儲過程和函數不一樣於已經介紹過的PL/SQL程序,咱們一般把PL/SQL程序稱爲無名塊,而存儲過程和函數是以命名的方式存儲於數據庫中的。和PL/SQL程序相比,存儲過程有不少優勢,具體概括以下: 
* 存儲過程和函數以命名的數據庫對象形式存儲於數據庫當中。存儲在數據庫中的優勢是很明顯的,由於代碼不保存在本地,用戶能夠在任何客戶機上登陸到數據庫,並調用或修改代碼。 
* 存儲過程和函數可由數據庫提供安全保證,要想使用存儲過程和函數,須要有存儲過程和函數的全部者的受權,只有被受權的用戶或建立者自己才能執行存儲過程或調用函數。 
* 存儲過程和函數的信息是寫入數據字典的,因此存儲過程能夠看做是一個公用模塊,用戶編寫的PL/SQL程序或其餘存儲過程均可以調用它(但存儲過程和函數不能調用PL/SQL程序)。一個重複使用的功能,能夠設計成爲存儲過程,好比:顯示一張工資統計表,能夠設計成爲存儲過程;一個常常調用的計算,能夠設計成爲存儲函數;根據僱員編號返回僱員的姓名,能夠設計成存儲函數。 
* 像其餘高級語言的過程和函數同樣,能夠傳遞參數給存儲過程或函數,參數的傳遞也有多種方式。存儲過程能夠有返回值,也能夠沒有返回值,存儲過程的返回值必須經過參數帶回;函數有必定的數據類型,像其餘的標準函數同樣,咱們能夠經過對函數名的調用返回函數值。 
   存儲過程和函數須要進行編譯,以排除語法錯誤,只有編譯經過才能調用。 
建立和刪除存儲過程  
建立存儲過程,須要有CREATE PROCEDURE或CREATE ANY PROCEDURE的系統權限。該權限可由系統管理員授予。建立一個存儲過程的基本語句以下: 
CREATE [OR REPLACE] PROCEDURE 存儲過程名[(參數[IN|OUT|IN OUT] 數據類型...)] 
{AS|IS} 
[說明部分] 
BEGIN 
可執行部分 
[EXCEPTION 
錯誤處理部分] 
END [過程名]; 
其中: 
可選關鍵字OR REPLACE 表示若是存儲過程已經存在,則用新的存儲過程覆蓋,一般用於存儲過程的重建。 
參數部分用於定義多個參數(若是沒有參數,就能夠省略)。參數有三種形式:IN、OUT和IN OUT。若是沒有指明參數的形式,則默認爲IN。 
關鍵字AS也能夠寫成IS,後跟過程的說明部分,能夠在此定義過程的局部變量。 
編寫存儲過程可使用任何文本編輯器或直接在SQL*Plus環境下進行,編寫好的存儲過程必需要在SQL*Plus環境下進行編譯,生成編譯代碼,原代碼和編譯代碼在編譯過程當中都會被存入數據庫。編譯成功的存儲過程就能夠在Oracle環境下進行調用了。 
一個存儲過程在不須要時能夠刪除。刪除存儲過程的人是過程的建立者或者擁有DROP ANY PROCEDURE系統權限的人。刪除存儲過程的語法以下: 
DROP PROCEDURE 存儲過程名; 
若是要從新編譯一個存儲過程,則只能是過程的建立者或者擁有ALTER ANY PROCEDURE系統權限的人。語法以下: 
ALTER PROCEDURE 存儲過程名 COMPILE; 
執行(或調用)存儲過程的人是過程的建立者或是擁有EXECUTE ANY PROCEDURE系統權限的人或是被擁有者授予EXECUTE權限的人。執行的方法以下: 
方法1: 
EXECUTE 模式名.存儲過程名[(參數...)]; 
方法2: 
BEGIN 
模式名.存儲過程名[(參數...)]; 
END; 
傳遞的參數必須與定義的參數類型、個數和順序一致(若是參數定義了默認值,則調用時能夠省略參數)。參數能夠是變量、常量或表達式,用法參見下一節。 
若是是調用本帳戶下的存儲過程,則模式名能夠省略。要調用其餘帳戶編寫的存儲過程,則模式名必需要添加。 
如下是一個生成和調用簡單存儲過程的訓練。注意要事先授予建立存儲過程的權限。 
【訓練1】  建立一個顯示僱員總人數的存儲過程。 
步驟1:登陸SCOTT帳戶(或學生我的帳戶)。 
步驟2:在SQL*Plus輸入區中,輸入如下存儲過程: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE PROCEDURE EMP_COUNT  
  2. AS  
  3. V_TOTAL NUMBER(10);  
  4. BEGIN  
  5.  SELECT COUNT(*) INTO V_TOTAL FROM EMP;  
  6.  DBMS_OUTPUT.PUT_LINE('僱員總人數爲:'||V_TOTAL);  
  7. END;  

步驟3:按「執行」按鈕進行編譯。 
若是存在錯誤,就會顯示: 
警告: 建立的過程帶有編譯錯誤。 
若是存在錯誤,對腳本進行修改,直到沒有錯誤產生。 
若是編譯結果正確,將顯示: 
Sql代碼   收藏代碼
  1. 過程已建立。  

步驟4:調用存儲過程,在輸入區中輸入如下語句並執行: 
Sql代碼   收藏代碼
  1. EXECUTE EMP_COUNT;  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 僱員總人數爲:14  
  2.         PL/SQL 過程已成功完成。  

說明:在該訓練中,V_TOTAL變量是存儲過程定義的局部變量,用於接收查詢到的僱員總人數。 
注意:在SQL*Plus中輸入存儲過程,按「執行」按鈕是進行編譯,不是執行存儲過程。 
  若是在存儲過程當中引用了其餘用戶的對象,好比表,則必須有其餘用戶授予的對象訪問權限。一個存儲過程一旦編譯成功,就能夠由其餘用戶或程序來引用。但存儲過程或函數的全部者必須授予其餘用戶執行該過程的權限。 
存儲過程沒有參數,在調用時,直接寫過程名便可。 
【訓練2】  在PL/SQL程序中調用存儲過程。 
步驟1:登陸SCOTT帳戶。 
步驟2:受權STUDENT帳戶使用該存儲過程,即在SQL*Plus輸入區中,輸入如下的命令: 
Sql代碼   收藏代碼
  1. GRANT EXECUTE ON EMP_COUNT TO STUDENT  

Sql代碼   收藏代碼
  1. 受權成功。  

步驟3:登陸STUDENT帳戶,在SQL*Plus輸入區中輸入如下程序: 
Sql代碼   收藏代碼
  1. SET SERVEROUTPUT ON  
  2.         BEGIN  
  3.         SCOTT.EMP_COUNT;  
  4.         END;  

步驟4:執行以上程序,結果爲: 
Sql代碼   收藏代碼
  1. 僱員總人數爲:14  
  2.         PL/SQL 過程已成功完成。   

  說明:在本例中,存儲過程是由SCOTT帳戶建立的,STUDEN帳戶得到SCOTT帳戶的受權後,才能調用該存儲過程。 
  注意:在程序中調用存儲過程,使用了第二種語法。 
【訓練3】  編寫顯示僱員信息的存儲過程EMP_LIST,並引用EMP_COUNT存儲過程。 
步驟1:在SQL*Plus輸入區中輸入並編譯如下存儲過程: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE PROCEDURE EMP_LIST  
  2.         AS  
  3.          CURSOR emp_cursor IS   
  4.         SELECT empno,ename FROM emp;  
  5.         BEGIN  
  6. FOR Emp_record IN emp_cursor LOOP     
  7.     DBMS_OUTPUT.PUT_LINE(Emp_record.empno||Emp_record.ename);  
  8.         END LOOP;  
  9.         EMP_COUNT;  
  10.         END;  

執行結果: 
Sql代碼   收藏代碼
  1. 過程已建立。  

步驟2:調用存儲過程,在輸入區中輸入如下語句並執行: 
Sql代碼   收藏代碼
  1. EXECUTE EMP_LIST  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 7369SMITH  
  2. 7499ALLEN  
  3. 7521WARD  
  4. 7566JONES  
  5.             執行結果:  
  6.         僱員總人數爲:14  
  7.         PL/SQL 過程已成功完成。  

說明:以上的EMP_LIST存儲過程當中定義並使用了遊標,用來循環顯示全部僱員的信息。而後調用已經成功編譯的存儲過程EMP_COUNT,用來附加顯示僱員總人數。經過EXECUTE命令來執行EMP_LIST存儲過程。 
【練習1】編寫顯示部門信息的存儲過程DEPT_LIST,要求統計出部門個數。 
參數傳遞  
參數的做用是向存儲過程傳遞數據,或從存儲過程得到返回結果。正確的使用參數能夠大大增長存儲過程的靈活性和通用性。 
參數的類型有三種,以下所示。 
Sql代碼   收藏代碼
  1. IN  定義一個輸入參數變量,用於傳遞參數給存儲過程  
  2. OUT 定義一個輸出參數變量,用於從存儲過程獲取數據  
  3. IN OUT  定義一個輸入、輸出參數變量,兼有以上二者的功能  

參數的定義形式和做用以下: 
參數名 IN 數據類型 DEFAULT 值; 
定義一個輸入參數變量,用於傳遞參數給存儲過程。在調用存儲過程時,主程序的實際參數能夠是常量、有值變量或表達式等。DEFAULT 關鍵字爲可選項,用來設定參數的默認值。若是在調用存儲過程時不指明參數,則參數變量取默認值。在存儲過程當中,輸入變量接收主程序傳遞的值,但不能對其進行賦值。 
參數名 OUT 數據類型; 
定義一個輸出參數變量,用於從存儲過程獲取數據,即變量從存儲過程當中返回值給主程序。 
在調用存儲過程時,主程序的實際參數只能是一個變量,而不能是常量或表達式。在存儲過程當中,參數變量只能被賦值而不能將其用於賦值,在存儲過程當中必須給輸出變量至少賦值一次。 
參數名 IN OUT 數據類型 DEFAULT 值; 
定義一個輸入、輸出參數變量,兼有以上二者的功能。在調用存儲過程時,主程序的實際參數只能是一個變量,而不能是常量或表達式。DEFAULT 關鍵字爲可選項,用來設定參數的默認值。在存儲過程當中,變量接收主程序傳遞的值,同時能夠參加賦值運算,也能夠對其進行賦值。在存儲過程當中必須給變量至少賦值一次。 
若是省略IN、OUT或IN OUT,則默認模式是IN。 
【訓練1】  編寫給僱員增長工資的存儲過程CHANGE_SALARY,經過IN類型的參數傳遞要增長工資的僱員編號和增長的工資額。 
步驟1:登陸SCOTT帳戶。 
  步驟2:在SQL*Plus輸入區中輸入如下存儲過程並執行: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE PROCEDURE CHANGE_SALARY(P_EMPNO IN NUMBER DEFAULT 7788,P_RAISE NUMBER DEFAULT 10)  
  2.         AS  
  3.          V_ENAME VARCHAR2(10);  
  4. V_SAL NUMBER(5);  
  5.         BEGIN  
  6.         SELECT ENAME,SAL INTO V_ENAME,V_SAL FROM EMP WHERE EMPNO=P_EMPNO;  
  7.          UPDATE EMP SET SAL=SAL+P_RAISE WHERE EMPNO=P_EMPNO;  
  8.          DBMS_OUTPUT.PUT_LINE('僱員'||V_ENAME||'的工資被改成'||TO_CHAR(V_SAL+P_RAISE));  
  9. COMMIT;  
  10.         EXCEPTION  
  11.          WHEN OTHERS THEN  
  12.         DBMS_OUTPUT.PUT_LINE('發生錯誤,修改失敗!');  
  13.         ROLLBACK;  
  14.         END;  

執行結果爲: 
Sql代碼   收藏代碼
  1. 過程已建立。  

步驟3:調用存儲過程,在輸入區中輸入如下語句並執行: 
Sql代碼   收藏代碼
  1. EXECUTE CHANGE_SALARY(7788,80)  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 僱員SCOTT的工資被改成3080   

說明:從執行結果能夠看到,僱員SCOTT的工資已由原來的3000改成3080。 
參數的值由調用者傳遞,傳遞的參數的個數、類型和順序應該和定義的一致。若是順序不一致,能夠採用如下調用方法。如上例,執行語句能夠改成: 
 EXECUTE CHANGE_SALARY(P_RAISE=>80,P_EMPNO=>7788); 
  能夠看出傳遞參數的順序發生了變化,而且明確指出了參數名和要傳遞的值,=>運算符左側是參數名,右側是參數表達式,這種賦值方法的意義較清楚。 
【練習1】建立插入僱員的存儲過程INSERT_EMP,並將僱員編號等做爲參數。 
在設計存儲過程的時候,也能夠爲參數設定默認值,這樣調用者就能夠不傳遞或少傳遞參數了。 
【訓練2】  調用存儲過程CHANGE_SALARY,不傳遞參數,使用默認參數值。 
在SQL*Plus輸入區中輸入如下命令並執行: 
Sql代碼   收藏代碼
  1. EXECUTE CHANGE_SALARY  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 僱員SCOTT的工資被改成3090   

說明:在存儲過程的調用中沒有傳遞參數,而是採用了默認值7788和10,即默認僱員號爲7788,增長的工資爲10。 
【訓練3】  使用OUT類型的參數返回存儲過程的結果。 
步驟1:登陸SCOTT帳戶。 
步驟2:在SQL*Plus輸入區中輸入並編譯如下存儲過程: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE PROCEDURE EMP_COUNT(P_TOTAL OUT NUMBER)  
  2.         AS  
  3.         BEGIN  
  4.         SELECT COUNT(*) INTO P_TOTAL FROM EMP;  
  5.         END;  

執行結果爲: 
Sql代碼   收藏代碼
  1. 過程已建立。  

步驟3:輸入如下程序並執行: 
Sql代碼   收藏代碼
  1. DECLARE  
  2.         V_EMPCOUNT NUMBER;  
  3.         BEGIN  
  4.         EMP_COUNT(V_EMPCOUNT);  
  5.         DBMS_OUTPUT.PUT_LINE('僱員總人數爲:'||V_EMPCOUNT);  
  6.         END;  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 僱員總人數爲:14  
  2.         PL/SQL 過程已成功完成。  

    說明:在存儲過程當中定義了OUT類型的參數P_TOTAL,在主程序調用該存儲過程時,傳遞了參數V_EMPCOUNT。在存儲過程當中的SELECT...INTO...語句中對P_TOTAL進行賦值,賦值結果由V_EMPCOUNT變量帶回給主程序並顯示。 
以上程序要覆蓋同名的EMP_COUNT存儲過程,若是不使用OR REPLACE選項,就會出現如下錯誤: 
Sql代碼   收藏代碼
  1. ERROR 位於第 1 行:  
  2.         ORA-00955: 名稱已由現有對象使用。  

【練習2】建立存儲過程,使用OUT類型參數得到僱員經理名。 
【訓練4】  使用IN OUT類型的參數,給電話號碼增長區碼。 
步驟1:登陸SCOTT帳戶。 
步驟2:在SQL*Plus輸入區中輸入並編譯如下存儲過程: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE PROCEDURE ADD_REGION(P_HPONE_NUM IN OUT VARCHAR2)  
  2.         AS  
  3.         BEGIN  
  4.          P_HPONE_NUM:='0755-'||P_HPONE_NUM;  
  5.         END;  

執行結果爲: 
Sql代碼   收藏代碼
  1. 過程已建立。  

步驟3:輸入如下程序並執行: 
Sql代碼   收藏代碼
  1. SET SERVEROUTPUT ON  
  2. DECLARE  
  3. V_PHONE_NUM VARCHAR2(15);  
  4. BEGIN  
  5. V_PHONE_NUM:='26731092';  
  6. ADD_REGION(V_PHONE_NUM);  
  7. DBMS_OUTPUT.PUT_LINE('新的電話號碼:'||V_PHONE_NUM);  
  8. END;  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 新的電話號碼:0755-26731092  
  2.         PL/SQL 過程已成功完成。  

說明:變量V_HPONE_NUM既用來向存儲過程傳遞舊電話號碼,也用來向主程序返回新號碼。新的號碼在原來基礎上增長了區號0755和-。 
建立和刪除存儲函數  
  建立函數,須要有CREATE PROCEDURE或CREATE ANY PROCEDURE的系統權限。該權限可由系統管理員授予。建立存儲函數的語法和建立存儲過程的相似,即 
CREATE [OR REPLACE] FUNCTION 函數名[(參數[IN] 數據類型...)] 
RETURN 數據類型 
{AS|IS} 
[說明部分] 
BEGIN 
可執行部分 
RETURN (表達式) 
[EXCEPTION 
    錯誤處理部分] 
END [函數名]; 
其中,參數是可選的,但只能是IN類型(IN關鍵字能夠省略)。 
在定義部分的RETURN 數據類型,用來表示函數的數據類型,也就是返回值的類型,此部分不可省略。 
在可執行部分的RETURN(表達式),用來生成函數的返回值,其表達式的類型應該和定義部分說明的函數返回值的數據類型一致。在函數的執行部分能夠有多個RETURN語句,但只有一個RETURN語句會被執行,一旦執行了RETURN語句,則函數結束並返回調用環境。 
一個存儲函數在不須要時能夠刪除,但刪除的人應是函數的建立者或者是擁有DROP ANY PROCEDURE系統權限的人。其語法以下: 
DROP FUNCTION 函數名; 
從新編譯一個存儲函數時,編譯的人應是函數的建立者或者擁有ALTER ANY PROCEDURE系統權限的人。從新編譯一個存儲函數的語法以下: 
ALTER PROCEDURE 函數名 COMPILE; 
函數的調用者應是函數的建立者或擁有EXECUTE ANY PROCEDURE系統權限的人,或是被函數的擁有者授予了函數執行權限的帳戶。函數的引用和存儲過程不一樣,函數要出如今程序體中,能夠參加表達式的運算或單獨出如今表達式中,其形式以下: 
變量名:=函數名(...) 
【訓練1】  建立一個經過僱員編號返回僱員名稱的函數GET_EMP_NAME。 
步驟1:登陸SCOTT帳戶。 
步驟2:在SQL*Plus輸入區中輸入如下存儲函數並編譯: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE FUNCTION GET_EMP_NAME(P_EMPNO NUMBER DEFAULT 7788)  
  2.         RETURN VARCHAR2  
  3.         AS  
  4.          V_ENAME VARCHAR2(10);  
  5.         BEGIN  
  6.         ELECT ENAME INTO V_ENAME FROM EMP WHERE EMPNO=P_EMPNO;  
  7. RETURN(V_ENAME);  
  8. EXCEPTION  
  9.  WHEN NO_DATA_FOUND THEN  
  10.   DBMS_OUTPUT.PUT_LINE('沒有該編號僱員!');  
  11.   RETURN (NULL);  
  12.  WHEN TOO_MANY_ROWS THEN  
  13.   DBMS_OUTPUT.PUT_LINE('有重複僱員編號!');  
  14.   RETURN (NULL);  
  15.  WHEN OTHERS THEN  
  16.   DBMS_OUTPUT.PUT_LINE('發生其餘錯誤!');  
  17.   RETURN (NULL);  
  18. END;  

步驟3:調用該存儲函數,輸入並執行如下程序: 
Sql代碼   收藏代碼
  1. BEGIN  
  2.         DBMS_OUTPUT.PUT_LINE('僱員7369的名稱是:'|| GET_EMP_NAME(7369));  
  3.          DBMS_OUTPUT.PUT_LINE('僱員7839的名稱是:'|| GET_EMP_NAME(7839));  
  4.         END;  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 僱員7369的名稱是:SMITH  
  2.         僱員7839的名稱是:KING  
  3.         PL/SQL 過程已成功完成。  

說明:函數的調用直接出如今程序的DBMS_OUTPUT.PUT_LINE語句中,做爲字符串表達式的一部分。若是輸入了錯誤的僱員編號,就會在函數的錯誤處理部分輸出錯誤信息。試修改僱員編號,從新運行調用部分。 
【練習1】建立一個經過部門編號返回部門名稱的存儲函數GET_DEPT_NAME。 
   【練習2】將函數的執行權限授予STUDENT帳戶,而後登陸STUDENT帳戶調用。 
存儲過程和函數的查看  
能夠經過對數據字典的訪問來查詢存儲過程或函數的有關信息,若是要查詢當前用戶的存儲過程或函數的源代碼,能夠經過對USER_SOURCE數據字典視圖的查詢獲得。USER_SOURCE的結構以下: 
Sql代碼   收藏代碼
  1. DESCRIBE USER_SOURCE  

結果爲: 
Sql代碼   收藏代碼
  1. 名稱                                      是否爲空? 類型  
  2.         ------------------------------------------------------------- ------------- -----------------------  
  3.  NAME                                               VARCHAR2(30)  
  4.  TYPE                                               VARCHAR2(12)  
  5.  LINE                                               NUMBER  
  6.  TEXT                                               VARCHAR2(4000)  

  說明:裏面按行存放着過程或函數的腳本,NAME是過程或函數名,TYPE 表明類型(PROCEDURE或FUNCTION),LINE是行號,TEXT 爲腳本。 
【訓練1】  查詢過程EMP_COUNT的腳本。 
在SQL*Plus中輸入並執行以下查詢: 
Sql代碼   收藏代碼
  1. select TEXT  from user_source WHERE NAME='EMP_COUNT';  

結果爲: 
Sql代碼   收藏代碼
  1. TEXT  
  2. --------------------------------------------------------------------------------  
  3. PROCEDURE EMP_COUNT(P_TOTAL OUT NUMBER)  
  4. AS  
  5. BEGIN  
  6.  SELECT COUNT(*) INTO P_TOTAL FROM EMP;  
  7. END;  

【訓練2】  查詢過程GET_EMP_NAME的參數。 
在SQL*Plus中輸入並執行以下查詢: 
Sql代碼   收藏代碼
  1. DESCRIBE GET_EMP_NAME  

結果爲: 
Sql代碼   收藏代碼
  1. FUNCTION GET_EMP_NAME RETURNS VARCHAR2  
  2.         參數名稱            類型          輸入/輸出默認值?  
  3.         ----------------------------------------- ----------------------------------- ----------------- -------------  
  4.         P_EMPNO             NUMBER(4) IN     DEFAULT  

【訓練3】  在發生編譯錯誤時,顯示錯誤。 
Sql代碼   收藏代碼
  1. SHOW ERRORS  

如下是一段編譯錯誤顯示: 
Sql代碼   收藏代碼
  1. LINE/COL ERROR  
  2.         ------------- -----------------------------------------------------------------  
  3.         4/2       PL/SQL: SQL Statement ignored  
  4.         4/36      PLS-00201: 必須說明標識符 'EMPP'  

  說明:查詢一個存儲過程或函數是不是有效狀態(即編譯成功),可使用數據字典USER_OBJECTS的STATUS列。 
【訓練4】  查詢EMP_LIST存儲過程是否可用: 
Sql代碼   收藏代碼
  1. SELECT STATUS FROM USER_OBJECTS WHERE OBJECT_NAME='EMP_LIST';  

結果爲: 
Sql代碼   收藏代碼
  1. STATUS  
  2.         ------------  
  3.         VALID  

說明:VALID表示該存儲過程有效(即經過編譯),INVALID表示存儲過程無效或須要從新編譯。當Oracle調用一個無效的存儲過程或函數時,首先試圖對其進行編譯,若是編譯成功則將狀態置成VALID並執行,不然給出錯誤信息。 
當一個存儲過程編譯成功,狀態變爲VALID,會不會在某些狀況下變成INVALID。結論是徹底可能的。好比一個存儲過程當中包含對錶的查詢,若是表被修改或刪除,存儲過程就會變成無效INVALID。因此要注意存儲過程和函數對其餘對象的依賴關係。 
若是要檢查存儲過程或函數的依賴性,能夠經過查詢數據字典USER_DENPENDENCIES來肯定,該表結構以下: 
Sql代碼   收藏代碼
  1. DESCRIBE USER_DEPENDENCIES;  

結果: 
Sql代碼   收藏代碼
  1. 名稱                     是否爲空? 類型  
  2.         -------------------------------------------------------------- ------------- ----------------------------  
  3.          NAME            NOT NULL   VARCHAR2(30)  
  4.          TYPE                       VARCHAR2(12)  
  5.         REFERENCED_OWNER                                VARCHAR2(30)  
  6.  REFERENCED_NAME                                VARCHAR2(64)  
  7.  REFERENCED_TYPE                                VARCHAR2(12)  
  8. REFERENCED_LINK_NAME                            VARCHAR2(128)  
  9.         SCHEMAID                                        NUMBER  
  10.          DEPENDENCY_TYPE                                VARCHAR2(4)  

  說明:NAME爲實體名,TYPE爲實體類型,REFERENCED_OWNER爲涉及到的實體擁有者帳戶,REFERENCED_NAME爲涉及到的實體名,REFERENCED_TYPE 爲涉及到的實體類型。 
【訓練5】  查詢EMP_LIST存儲過程的依賴性。 
Sql代碼   收藏代碼
  1. SELECT REFERENCED_NAME,REFERENCED_TYPE FROM USER_DEPENDENCIES WHERE NAME='EMP_LIST';  

執行結果: 
Sql代碼   收藏代碼
  1. REFERENCED_NAME                                         REFERENCED_TYPE  
  2.         ------------------------------------------------------------------------------------------ ----------------------------  
  3. STANDARD                                                PACKAGE  
  4.         SYS_STUB_FOR_PURITY_ANALYSIS                            PACKAGE  
  5.         DBMS_OUTPUT                                                 PACKAGE  
  6.         DBMS_OUTPUT                                             SYNONYM  
  7. DBMS_OUTPUT                      NON-EXISTENT  
  8.         EMP                                                         TABLE  
  9.         EMP_COUNT                                                   PROCEDURE  

  說明:能夠看出存儲過程EMP_LIST依賴一些系統包、EMP表和EMP_COUNT存儲過程。若是刪除了EMP表或EMP_COUNT存儲過程,EMP_LIST將變成無效。 
還有一種狀況須要咱們注意:若是一個用戶A被授予執行屬於用戶B的一個存儲過程的權限,在用戶B的存儲過程當中,訪問到用戶C的表,用戶B被授予訪問用戶C的表的權限,但用戶A沒有被授予訪問用戶C表的權限,那麼用戶A調用用戶B的存儲過程是失敗的仍是成功的呢?答案是成功的。若是讀者有興趣,不妨進行一下實際測試。 

 
包的概念和組成  
包是用來存儲相關程序結構的對象,它存儲於數據字典中。包由兩個分離的部分組成:包頭(PACKAGE)和包體(PACKAGE BODY)。包頭是包的說明部分,是對外的操做接口,對應用是可見的;包體是包的代碼和實現部分,對應用來講是不可見的黑盒。 
包中能夠包含的程序結構以下所示。 
Sql代碼   收藏代碼
  1. 過程(PROCUDURE)   帶參數的命名的程序模塊  
  2. 函數(FUNCTION)    帶參數、具備返回值的命名的程序模塊  
  3. 變量(VARIABLE)    存儲變化的量的存儲單元  
  4. 常量(CONSTANT)    存儲不變的量的存儲單元  
  5. 遊標(CURSOR)  用戶定義的數據操做緩存區,在可執行部分使用  
  6. 類型(TYPE)    用戶定義的新的結構類型  
  7. 異常(EXCEPTION)   在標準包中定義或由用戶自定義,用於處理程序錯誤  

說明部分能夠出如今包的三個不一樣的部分:出如今包頭中的稱爲公有元素,出如今包體中的稱爲私有元素,出如今包體的過程(或函數)中的稱爲局部變量。它們的性質有所不一樣,以下所示。 
Sql代碼   收藏代碼
  1. 公有元素(PUBLIC)    在包頭中說明,在包體中具體定義 在包外可見並能夠訪問,對整個應用的全過程有效  
  2. 私有元素(PRIVATE)   在包體的說明部分說明  只能被包內部的其餘部分訪問  
  3. 局部變量(LOCAL) 在過程或函數的說明部分說明   只能在定義變量的過程或函數中使用  

在包體中出現的過程或函數,若是須要對外公用,就必須在包頭中說明,包頭中的說明應該和包體中的說明一致。
包有如下優勢:  
* 包能夠方便地將存儲過程和函數組織到一塊兒,每一個包又是相互獨立的。在不一樣的包中,過程、函數均可以重名,這解決了在同一個用戶環境中命名的衝突問題。 
* 包加強了對存儲過程和函數的安全管理,對整個包的訪問權只需一次授予。 
  * 在同一個會話中,公用變量的值將被保留,直到會話結束。 
* 區分了公有過程和私有過程,包體的私有過程增長了過程和函數的保密性。 
* 包在被首次調用時,就做爲一個總體被所有調入內存,減小了屢次訪問過程或函數的I/O次數。 
建立包和包體  
包由包頭和包體兩部分組成,包的建立應該先建立包頭部分,而後建立包體部分。建立、刪除和編譯包的權限同建立、刪除和編譯存儲過程的權限相同。 
建立包頭的簡要語句以下: 
CREATE [OR REPLACE] PACKAGE 包名 
{IS|AS} 
公有變量定義 
公有類型定義 
公有遊標定義 
公有異常定義 
函數說明 
過程說明 
END; 
建立包體的簡要語法以下: 
CREATE [OR REPLACE] PACKAGE BODY 包名 
{IS|AS} 
私有變量定義 
私有類型定義 
私有遊標定義 
私有異常定義 
函數定義 
過程定義 
END; 
包的其餘操做命令包括: 
刪除包頭: 
DROP PACKAGE 包頭名 
刪除包體: 
DROP PACKAGE BODY 包體名 
從新編譯包頭: 
ALTER PACKAGE 包名 COMPILE PACKAGE 
從新編譯包體: 
ALTER PACKAGE 包名 COMPILE PACKAGE BODY 
在包頭中說明的對象能夠在包外調用,調用的方法和調用單獨的過程或函數的方法基本相同,唯一的區別就是要在調用的過程或函數名前加上包的名字(中間用「.」分隔)。但要注意,不一樣的會話將單獨對包的公用變量進行初始化,因此不一樣的會話對包的調用屬於不一樣的應用。 
系統包  
Oracle預約義了不少標準的系統包,這些包能夠在應用中直接使用,好比在訓練中咱們使用的DBMS_OUTPUT包,就是系統包。PUT_LINE是該包的一個函數。經常使用系統包下所示。 
Sql代碼   收藏代碼
  1. DBMS_OUTPUT 在SQL*Plus環境下輸出信息  
  2. DBMS_DDL    編譯過程函數和包  
  3. DBMS_SESSION    改變用戶的會話,初始化包等  
  4. DBMS_TRANSACTION    控制數據庫事務  
  5. DBMS_MAIL   鏈接Oracle*Mail  
  6. DBMS_LOCK   進行復雜的鎖機制管理  
  7. DBMS_ALERT  識別數據庫事件告警  
  8. DBMS_PIPE   經過管道在會話間傳遞信息  
  9. DBMS_JOB    管理Oracle的做業  
  10. DBMS_LOB    操縱大對象  
  11. DBMS_SQL    執行動態SQL語句  

包的應用  
在SQL*Plus環境下,包和包體能夠分別編譯,也能夠一塊兒編譯。若是分別編譯,則要先編譯包頭,後編譯包體。若是在一塊兒編譯,則包頭寫在前,包體在後,中間用「/」分隔。 
能夠將已經存在的存儲過程或函數添加到包中,方法是去掉過程或函數建立語句的CREATE OR REPLACE部分,將存儲過程或函數複製到包體中 ,而後從新編譯便可。 
   若是須要將私有過程或函數變成共有過程或函數的話,將過程或函數說明部分複製到包頭說明部分,而後從新編譯就能夠了。 
【訓練1】  建立管理僱員信息的包EMPLOYE,它具備從EMP表得到僱員信息,修改僱員名稱,修改僱員工資和寫回EMP表的功能。 
步驟1:登陸SCOTT帳戶,輸入如下代碼並編譯: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE PACKAGE EMPLOYE --包頭部分   
  2.         IS  
  3.  PROCEDURE SHOW_DETAIL;   
  4.  PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER);   
  5.  PROCEDURE SAVE_EMPLOYE;   
  6.  PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2);   
  7. PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER);   
  8.         END EMPLOYE;  
  9.         /  
  10.         CREATE OR REPLACE PACKAGE BODY EMPLOYE --包體部分   
  11.         IS  
  12.  EMPLOYE EMP%ROWTYPE;  
  13.         -------------- 顯示僱員信息 ---------------  
  14.         PROCEDURE SHOW_DETAIL  
  15.         AS  
  16.         BEGIN  
  17. DBMS_OUTPUT.PUT_LINE(‘----- 僱員信息 -----’);     
  18.         DBMS_OUTPUT.PUT_LINE('僱員編號:'||EMPLOYE.EMPNO);  
  19.         DBMS_OUTPUT.PUT_LINE('僱員名稱:'||EMPLOYE.ENAME);  
  20.           DBMS_OUTPUT.PUT_LINE('僱員職務:'||EMPLOYE.JOB);  
  21.          DBMS_OUTPUT.PUT_LINE('僱員工資:'||EMPLOYE.SAL);  
  22.          DBMS_OUTPUT.PUT_LINE('部門編號:'||EMPLOYE.DEPTNO);  
  23.         END SHOW_DETAIL;  
  24. ----------------- 從EMP表取得一個僱員 --------------------  
  25.          PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER)  
  26.         AS  
  27.         BEGIN  
  28.         SELECT * INTO EMPLOYE FROM EMP WHERE    EMPNO=P_EMPNO;  
  29.         DBMS_OUTPUT.PUT_LINE('獲取僱員'||EMPLOYE.ENAME||'信息成功');  
  30.          EXCEPTION  
  31.          WHEN OTHERS THEN  
  32.            DBMS_OUTPUT.PUT_LINE('獲取僱員信息發生錯誤!');  
  33.         END GET_EMPLOYE;  
  34. ---------------------- 保存僱員到EMP表 --------------------------  
  35.         PROCEDURE SAVE_EMPLOYE  
  36.         AS  
  37.         BEGIN  
  38.         UPDATE EMP SET ENAME=EMPLOYE.ENAME, SAL=EMPLOYE.SAL WHERE EMPNO=  
  39.     EMPLOYE.EMPNO;  
  40.      DBMS_OUTPUT.PUT_LINE('僱員信息保存完成!');  
  41.         END SAVE_EMPLOYE;  
  42. ---------------------------- 修改僱員名稱 ------------------------------  
  43.         PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2)  
  44.          AS  
  45.         BEGIN  
  46.          EMPLOYE.ENAME:=P_NEWNAME;  
  47.          DBMS_OUTPUT.PUT_LINE('修更名稱完成!');  
  48.         END CHANGE_NAME;  
  49. ---------------------------- 修改僱員工資 --------------------------  
  50.         PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER)  
  51.         AS  
  52.         BEGIN  
  53.          EMPLOYE.SAL:=P_NEWSAL;  
  54.          DBMS_OUTPUT.PUT_LINE('修改工資完成!');  
  55.         END CHANGE_SAL;  
  56.         END EMPLOYE;  

步驟2:獲取僱員7788的信息: 
Sql代碼   收藏代碼
  1. SET SERVEROUTPUT ON  
  2.         EXECUTE EMPLOYE.GET_EMPLOYE(7788);  

結果爲: 
Sql代碼   收藏代碼
  1. 獲取僱員SCOTT信息成功  
  2.         PL/SQL 過程已成功完成。  

步驟3:顯示僱員信息: 
Sql代碼   收藏代碼
  1. EXECUTE EMPLOYE.SHOW_DETAIL;  

結果爲: 
Sql代碼   收藏代碼
  1. ------------------ 僱員信息 ------------------  
  2.         僱員編號:7788  
  3.         僱員名稱:SCOTT  
  4.         僱員職務:ANALYST  
  5.         僱員工資:3000  
  6.         部門編號:20  
  7.         PL/SQL 過程已成功完成。  

步驟4:修改僱員工資: 
Sql代碼   收藏代碼
  1. EXECUTE EMPLOYE.CHANGE_SAL(3800);  

結果爲: 
Sql代碼   收藏代碼
  1. 修改工資完成!  
  2.         PL/SQL 過程已成功完成。  

步驟5:將修改的僱員信息存入EMP表 
Sql代碼   收藏代碼
  1. EXECUTE EMPLOYE.SAVE_EMPLOYE;  

結果爲: 
Sql代碼   收藏代碼
  1. 僱員信息保存完成!  
  2.         PL/SQL 過程已成功完成。  

說明:該包完成將EMP表中的某個僱員的信息取入內存記錄變量,在記錄變量中進行修改編輯,在確認顯示信息正確後寫回EMP表的功能。記錄變量EMPLOYE用來存儲取得的僱員信息,定義爲私有變量,只能被包的內部模塊訪問。 
  【練習1】爲包增長修改僱員職務和部門編號的功能。 

階段訓練  
下面的訓練經過定義和建立完整的包EMP_PK並綜合運用本章的知識,完成對僱員表的插入、刪除等功能,包中的主要元素解釋以下所示。 
Sql代碼   收藏代碼
  1. 程序結構    類  型    說    明  
  2. V_EMP_COUNT 公有變量    跟蹤僱員的總人數變化,插入、刪除僱員的同時修改該變量的值  
  3. INIT    公有過程    對包進行初始化,初始化僱員人數和工資修改的上、下限  
  4. LIST_EMP    公有過程    顯示僱員列表  
  5. INSERT_EMP  公有過程    經過編號插入新僱員  
  6. DELETE_EMP  公有過程    經過編號刪除僱員  
  7. CHANGE_EMP_SAL  公有過程    經過編號修改僱員工資  
  8. V_MESSAGE   私有變量    存放準備輸出的信息  
  9. C_MAX_SAL   私有變量    對工資修改的上限  
  10. C_MIN_SAL   私有變量    對工資修改的下限  
  11. SHOW_MESSAGE    私有過程    顯示私有變量V_MESSAGE中的信息  
  12. EXIST_EMP   私有函數    判斷某個編號的僱員是否存在,該函數被INSERT_EMP、DELETE_EMP和CHANGE_EMP_SAL等過程調用  

【訓練1】  完整的僱員包EMP_PK的建立和應用。 
步驟1:在SQL*Plus中登陸SCOTT帳戶,輸入如下包頭和包體部分,按「執行」按鈕編譯: 
Sql代碼   收藏代碼
  1. CREATE OR REPLACE PACKAGE EMP_PK   
  2.         --包頭部分   
  3.         IS  
  4.         V_EMP_COUNT NUMBER(5);                
  5.         --僱員人數  
  6.         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER);  --初始化  
  7.         PROCEDURE LIST_EMP;                       
  8.         --顯示僱員列表  
  9. PROCEDURE INSERT_EMP(P_EMPNO        NUMBER,P_ENAMEVARCHAR2,P_JOB VARCHAR2,  
  10.         P_SAL NUMBER);                        
  11.         --插入僱員  
  12.         PROCEDURE DELETE_EMP(P_EMPNO NUMBER);       --刪除僱員  
  13.          PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER);   
  14.         --修改僱員工資  
  15.         END EMP_PK;  
  16.         /CREATE OR REPLACE PACKAGE BODY EMP_PK  
  17.          --包體部分   
  18.         IS  
  19.         V_MESSAGE VARCHAR2(50); --顯示信息  
  20. V_MAX_SAL NUMBER(7); --工資上限  
  21.         V_MIN_SAL NUMBER(7); --工資下限  
  22.         FUNCTION EXIST_EMP(P_EMPNO NUMBER)  RETURN  BOOLEAN; --判斷僱員是否存在函數  
  23.         PROCEDURE SHOW_MESSAGE; --顯示信息過程  
  24.         ------------------------------- 初始化過程 ----------------------------  
  25.         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER)   
  26.         IS   
  27.         BEGIN  
  28.          SELECT COUNT(*) INTO V_EMP_COUNT FROM EMP;  
  29. V_MAX_SAL:=P_MAX;  
  30.          V_MIN_SAL:=P_MIN;  
  31.          V_MESSAGE:='初始化過程已經完成!';  
  32.          SHOW_MESSAGE;   
  33.         END INIT;  
  34. ---------------------------- 顯示僱員列表過程 ---------------------  
  35.         PROCEDURE LIST_EMP   
  36.          IS   
  37.         BEGIN  
  38. DBMS_OUTPUT.PUT_LINE('姓名       職務      工資');  
  39.         FOR emp_rec IN (SELECT * FROM EMP)  
  40.         LOOP  
  41.     DBMS_OUTPUT.PUT_LINE(RPAD(emp_rec.ename,10,'')||RPAD(emp_rec.job,10,' ')||TO_CHAR(emp_rec.sal));  
  42.          END LOOP;  
  43.          DBMS_OUTPUT.PUT_LINE('僱員總人數'||V_EMP_COUNT);  
  44.         END LIST_EMP;  
  45. ----------------------------- 插入僱員過程 -----------------------------  
  46.         PROCEDUREINSERT_EMP(P_EMPNO     NUMBER,P_ENAMEVARCHAR2,P_JOB    VARCHAR2,P_SAL NUMBER)  
  47.          IS   
  48.         BEGIN  
  49.         IF NOT EXIST_EMP(P_EMPNO) THEN  
  50.         INSERT INTO EMP(EMPNO,ENAME,JOB,SAL)        VALUES(P_EMPNO,P_ENAME,P_JOB,P_SAL);  
  51.         COMMIT;   
  52.         V_EMP_COUNT:=V_EMP_COUNT+1;  
  53.         V_MESSAGE:='僱員'||P_EMPNO||'已插入!';  
  54.         ELSE  
  55. V_MESSAGE:='僱員'||P_EMPNO||'已存在,不能插入!';  
  56.       END IF;  
  57.      SHOW_MESSAGE;   
  58.      EXCEPTION  
  59.     WHEN OTHERS THEN  
  60.      V_MESSAGE:='僱員'||P_EMPNO||'插入失敗!';  
  61.      SHOW_MESSAGE;  
  62.      END INSERT_EMP;  
  63. --------------------------- 刪除僱員過程 --------------------  
  64.          PROCEDURE DELETE_EMP(P_EMPNO NUMBER)   
  65.         IS   
  66.         BEGIN   
  67.         IF EXIST_EMP(P_EMPNO) THEN  
  68.         DELETE FROM EMP WHERE EMPNO=P_EMPNO;  
  69.         COMMIT;  
  70.          V_EMP_COUNT:=V_EMP_COUNT-1;  
  71.          V_MESSAGE:='僱員'||P_EMPNO||'已刪除!';  
  72.          ELSE  
  73. V_MESSAGE:='僱員'||P_EMPNO||'不存在,不能刪除!';  
  74.     END IF;  
  75.     SHOW_MESSAGE;  
  76.      EXCEPTION  
  77.      WHEN OTHERS THEN  
  78.      V_MESSAGE:='僱員'||P_EMPNO||'刪除失敗!';  
  79.      SHOW_MESSAGE;  
  80.     END DELETE_EMP;  
  81. --------------------------------------- 修改僱員工資過程 ------------------------------------  
  82.         PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER)   
  83.          IS   
  84.          BEGIN   
  85.          IF (P_SAL>V_MAX_SAL OR P_SAL<V_MIN_SAL) THEN  
  86.          V_MESSAGE:='工資超出修改範圍!';  
  87.         ELSIF NOT EXIST_EMP(P_EMPNO) THEN  
  88.         V_MESSAGE:='僱員'||P_EMPNO||'不存在,不能修改工資!';  
  89. ELSE  
  90.          UPDATE EMP SET SAL=P_SAL WHERE EMPNO=P_EMPNO;  
  91.         COMMIT;  
  92.         V_MESSAGE:='僱員'||P_EMPNO||'工資已經修改!';  
  93.         END IF;  
  94.         SHOW_MESSAGE;  
  95.         EXCEPTION  
  96.          WHEN OTHERS THEN  
  97.          V_MESSAGE:='僱員'||P_EMPNO||'工資修改失敗!';  
  98.          SHOW_MESSAGE;  
  99.          END CHANGE_EMP_SAL;  
  100. ---------------------------- 顯示信息過程 ----------------------------  
  101.          PROCEDURE SHOW_MESSAGE   
  102.         IS   
  103.         BEGIN  
  104.          DBMS_OUTPUT.PUT_LINE('提示信息:'||V_MESSAGE);  
  105.         END SHOW_MESSAGE;  
  106. ------------------------ 判斷僱員是否存在函數 -------------------  
  107.          FUNCTION EXIST_EMP(P_EMPNO NUMBER)  
  108.          RETURN BOOLEAN   
  109.          IS  
  110.         V_NUM NUMBER; --局部變量  
  111.         BEGIN  
  112.         SELECT COUNT(*) INTO V_NUM FROM EMP WHERE EMPNO=P_EMPNO;  
  113. IF V_NUM=1 THEN   
  114.            RETURN TRUE;  
  115.          ELSE  
  116.          RETURN FALSE;  
  117.         END IF;   
  118.         END EXIST_EMP;  
  119.         -----------------------------  
  120.         END EMP_PK;  
結果爲: 
Sql代碼   收藏代碼
  1. 程序包已建立。  
  2.         程序包主體已建立。  

步驟2:初始化包: 
Sql代碼   收藏代碼
  1. SET SERVEROUTPUT ON  
  2. EXECUTE EMP_PK.INIT(6000,600);  

顯示爲: 
Sql代碼   收藏代碼
  1. 提示信息:初始化過程已經完成!  

步驟3:顯示僱員列表: 
Sql代碼   收藏代碼
  1. EXECUTE EMP_PK.LIST_EMP;  

顯示爲: 
Sql代碼   收藏代碼
  1. 姓名          職務          工資  
  2.         SMITH       CLERK       1560  
  3.         ALLEN       SALESMAN    1936  
  4.         WARD        SALESMAN    1830  
  5.         JONES       MANAGER     2975  
  6.         ...  
  7.         僱員總人數:14  
  8.         PL/SQL 過程已成功完成。  

步驟4:插入一個新記錄: 
Sql代碼   收藏代碼
  1. EXECUTE EMP_PK.INSERT_EMP(8001,'小王','CLERK',1000);  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 提示信息:僱員8001已插入!  
  2. PL/SQL 過程已成功完成。  

步驟5:經過全局變量V_EMP_COUNT查看僱員人數: 
Sql代碼   收藏代碼
  1. BEGIN  
  2. DBMS_OUTPUT.PUT_LINE(EMP_PK.V_EMP_COUNT);  
  3. END;  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 15  
  2. PL/SQL 過程已成功完成。  

步驟6:刪除新插入記錄: 
Sql代碼   收藏代碼
  1. EXECUTE EMP_PK.DELETE_EMP(8001);  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 提示信息:僱員8001已刪除!  
  2.         PL/SQL 過程已成功完成。  

再次刪除該僱員: 
Sql代碼   收藏代碼
  1. EXECUTE EMP_PK.DELETE_EMP(8001);  

結果爲: 
Sql代碼   收藏代碼
  1. 提示信息:僱員8001不存在,不能刪除!  

步驟7:修改僱員工資: 
Sql代碼   收藏代碼
  1. EXECUTE EMP_PK.CHANGE_EMP_SAL(7788,8000);  

顯示結果爲: 
Sql代碼   收藏代碼
  1. 提示信息:工資超出修改範圍!  
  2.         PL/SQL 過程已成功完成。  

步驟8:受權其餘用戶調用包: 
若是是另一個用戶要使用該包,必須由包的全部者受權,下面授予STUDEN帳戶對該包的使用權: 
Sql代碼   收藏代碼
  1. GRANT EXECUTE ON EMP_PK TO STUDENT;  

每個新的會話要爲包中的公用變量開闢新的存儲空間,因此須要從新執行初始化過程。兩個會話的進程互不影響。 
步驟9:其餘用戶調用包。 
啓動另一個SQL*Plus,登陸STUDENT帳戶,執行如下過程: 
Sql代碼   收藏代碼
  1. SET SERVEROUTPUT ON  
  2.         EXECUTE SCOTT.EMP_PK. EMP_PK.INIT(5000,700);  

結果爲: 
Sql代碼   收藏代碼
  1. 提示信息:初始化過程已經完成!  
  2.         PL/SQL 過程已成功完成。  

說明:在初始化中設置僱員的總人數和修改工資的上、下限,初始化後V_EMP_COUNT爲14人,插入僱員後V_EMP_COUNT爲15人。V_EMP_COUNT爲公有變量,因此能夠在外部程序中使用DBMS_OUTPUT.PUT_LINE輸出,引用時用EMP_PK.V_EMP_COUNT的形式,說明所屬的包。而私有變量V_MAX_SAL和V_MIN_SAL不能被外部訪問,只能經過內部過程來修改。一樣,EXIST_EMP和SHOW_MESSAGE也是私有過程,也只能在過程體內被其餘模塊引用。 
注意:在最後一個步驟中,由於STUDENT模式調用了SCOTT模式的包,因此包名前要增長模式名SCOTT。不一樣的會話對包的調用屬於不一樣的應用,因此須要從新進行初始化。 
練習  
1.若是存儲過程的參數類型爲OUT,那麼調用時傳遞的參數應該爲: 
     A.常量 B.表達式                C.變量 D.均可以 
2.下列有關存儲過程的特色說法錯誤的是: 
     A.存儲過程不能將值傳回調用的主程序 
     B.存儲過程是一個命名的模塊 
     C.編譯的存儲過程存放在數據庫中 
     D.一個存儲過程能夠調用另外一個存儲過程 
3.下列有關函數的特色說法錯誤的是: 
     A.函數必須定義返回類型 
     B.函數參數的類型只能是IN 
     C.在函數體內能夠屢次使用RETURN語句 
     D.函數的調用應使用EXECUTE命令 
4.包中不能包含的元素爲: 
     A.存儲過程 B.存儲函數
     C.遊標    D.表 
5.下列有關包的使用說法錯誤的是: 
     A.在不一樣的包內模塊能夠重名 
     B.包的私有過程不能被外部程序調用 
     C.包體中的過程和函數必須在包頭部分說明 
     D.必須先建立包頭,而後建立包體 

黑色頭髮:http://heisetoufa.iteye.com/
相關文章
相關標籤/搜索