oracle 對象管理 09_過程函數與包

1、過程
    過程是執行一系列PL/SQL操做的組合程序塊,能夠向存儲過程傳遞參數,也能夠從存儲過程傳回參數,創建後
存儲在數據庫服務器上,可供屢次調用;能夠將商業邏輯、企業規則寫成函數或過程保存到數據庫中,以便共享。
1.建立過程
    create or replace procedure pro_name (var_var  in/out datatype)
    is/as 
        變量聲明區
    begin
        業務程序區
    exception
        異常區
    end;
2.過程的參數
a.in 能夠是常量,變量,varchar2類型在參數中不用指定大小
b.out 只能是變量
3.查詢過程的定義
    select dbms_metadata.get_ddl('PROCEDURE','PROCE_01') FROM DUAL;
    select text from user_source where name = 'PROCE_01';
4.過程依賴的表刪掉後,過程會變成invalid的,當表恢復後,過程不是系統自動維護,因此須要從新編譯:
    alter procedure PROCE_01 compile;
5.過程的調用
    exec procedure_name(parameters..);
6.過程使用
a.刪除指定員工記錄;
    CREATE OR REPLACE PROCEDURE DelEmp
       (v_empno IN employees.employee_id%TYPE) 
    AS
    No_result EXCEPTION;
    BEGIN
       DELETE FROM employees WHERE employee_id = v_empno;
       IF SQL%NOTFOUND THEN
          RAISE no_result;
       END IF;
       DBMS_OUTPUT.PUT_LINE('編碼爲'||v_empno||'的員工已被刪除!');
    EXCEPTION
       WHEN no_result THEN 
          DBMS_OUTPUT.PUT_LINE('舒適提示:你須要的數據不存在!');
       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
    END DelEmp;
    --調用
    DECLARE
        v1 employees.first_name%TYPE;
        v2 employees.salary%TYPE;
    BEGIN
       QueryEmp(100, v1, v2);
       DBMS_OUTPUT.PUT_LINE('姓名:'||v1);
       DBMS_OUTPUT.PUT_LINE('工資:'||v2);
    END;
b.使用存儲過程向departments表中插入數據。
    CREATE OR REPLACE PROCEDURE insert_dept
      (v_dept_id IN departments.department_id%TYPE,
       v_dept_name IN departments.department_name%TYPE,
       v_mgr_id IN departments.manager_id%TYPE,
       v_loc_id IN departments.location_id%TYPE)
    IS
       ept_null_error EXCEPTION;
       PRAGMA EXCEPTION_INIT(ept_null_error, -1400);
       ept_no_loc_id EXCEPTION;
       PRAGMA EXCEPTION_INIT(ept_no_loc_id, -2291);
    BEGIN
       INSERT INTO departments
       (department_id, department_name, manager_id, location_id)
       VALUES
       (v_dept_id, v_dept_name, v_mgr_id, v_loc_id);
       DBMS_OUTPUT.PUT_LINE('插入部門'||v_dept_id||'成功');
    EXCEPTION
       WHEN DUP_VAL_ON_INDEX THEN
          RAISE_APPLICATION_ERROR(-20000, '部門編碼不能重複');
       WHEN ept_null_error THEN
          RAISE_APPLICATION_ERROR(-20001, '部門編碼、部門名稱不能爲空');
       WHEN ept_no_loc_id THEN
          RAISE_APPLICATION_ERROR(-20002, '沒有該地點');
    END insert_dept;
7.刪除過程,不帶參數只用名稱
    DROP PROCEDURE [user.]Procudure_name;sql

2、函數
    是被命名的PL/SQL塊,用於返回特定的數據,必需要有return字句,在函數的任何地方均可以經過return表達
式語句從函數返回,這裏的表達式的值與函數定義中指定的返回數據類型一致
1.函數定義
    create or replace function funct_name (var_l  in/out datatype)
    return datatype
    is/as
    begin
      function_body;
    end;
2.函數的調用及參數傳遞
a.傳址法是指在調用函數時,將實際參數的地址指針傳遞給形式參數,使形式參數和實際參數指向內存中的同一
區域,從而實現參數數據的傳遞。這種方法又稱做參照法,即形式參數參照實際參數數據。輸入參數均採用傳址
法傳遞數據。
b.傳值法是指將實際參數的數據拷貝到形式參數,而不是傳遞實際參數的地址。默認時,輸出參數和輸入/輸出
參數均採用傳值法。在函數調用時,ORACLE將實際參數數據拷貝到輸入/輸出參數,而當函數正常運行退出時,
又將輸出形式參數和輸入/輸出形式參數數據拷貝到實際參數變量中。
c.調用函數
    DECLARE
      V_num NUMBER;
      V_sum NUMBER;
    BEGIN
      V_sum :=get_salary(10, v_num);
      DBMS_OUTPUT.PUT_LINE('部門號爲:10的工資總和:'||v_sum||',人數爲:'||v_num);
    END;
3.函數的使用
a.eg
    CREATE OR REPLACE FUNCTION demo_fun(
      Name VARCHAR2,--注意VARCHAR2不能給精度,如:VARCHAR2(10),其它相似
      Age INTEGER,
      Sex VARCHAR2 DEFAULT '男')
      RETURN VARCHAR2 
    AS
      V_var VARCHAR2(32);
    BEGIN
      V_var := name||':'||TO_CHAR(age)||'歲.'||sex;
      RETURN v_var;
    END;
    
    DECLARE 
      Var VARCHAR(32);
    BEGIN
      Var := demo_fun('user1', 30, sex => '男');
      DBMS_OUTPUT.PUT_LINE(var);
    
      Var := demo_fun('user2', age => 40, sex => '男');
      DBMS_OUTPUT.PUT_LINE(var);
    
      Var := demo_fun('user3', sex => '女', age => 20);
      DBMS_OUTPUT.PUT_LINE(var);
    END;
4.刪除函數
    drop function_name;
    
3、函數和過程的聯繫
1.受權
    GRANT EXECUTE ON procedure_name[function_name] TO user_naem [PUBLIC] [WITH GRANT OPTION]
2.函數與過程的區同
a.過程和函數的惟一區別是函數總向調用者返回數據,而過程則不返回數據;
b.過程和函數統稱爲PL/SQL子程序,他們是被命名的PL/SQL塊,均存儲在數據庫中,並經過輸入、輸出參
  數或輸入/輸出參數與其調用者交換信息;
c.若是須要返回多個值和不返回值,就使用過程;若是隻須要返回一個值,就使用函數;
d.過程通常用於執行一個指定的動做,函數通常用於計算和返回一個值;
e.能夠SQL語句內部(如表達式)調用函數來完成複雜的計算問題,但不能調用過程。因此這是函數的特點。
2.使用過程與函數具備以下優勢:
a.共同使用的代碼能夠只須要被編寫和測試一次,而被須要該代碼的任何應用程序(如:.NET、C++、JAVA
   、VB程序,也能夠是DLL庫)調用。
b.這種集中編寫、集中維護更新、你們共享(或重用)的方法,簡化了應用程序的開發和維護,提升了效率與性能。
c.這種模塊化的方法,使得能夠將一個複雜的問題、大的程序逐步簡化成幾個簡單的、小的程序部分,進行分別編
  寫、調試。所以使程序的結構清晰、簡單,也容易實現。
d.能夠在各個開發者之間提供處理數據、控制流程、提示信息等方面的一致性。
e.節省內存空間。它們以一種壓縮的形式被存儲在外存中,當被調用時才被放入內存進行處理。而且,若是多個用
  戶要執行相同的過程或函數時,就只須要在內存中加載一個該過程或函數。
f.提升數據的安全性與完整性。經過把一些對數據的操做放到過程或函數中,就能夠經過是否授予用戶有執行該過
  程或的權限,來限制某些用戶對數據進行這些操做。數據庫

4、包
    一種程序邏輯單元,包能夠將任何出如今塊聲明的語句 ( 過程 , 函數 , 遊標 , 遊標 , 類型 , 變量 ) 放於包
中 , 至關於一個容器。將聲明語句放入包中的好處是 : 用戶能夠從其餘 PL/SQL 塊中對其進行引用 , 所以包爲 
PL/SQL 提供了全程變量。包能夠重載過程和函數,在包內能夠用同一個名字聲明多個程序,在運行時根據參
數的數目和數據類型調用正確的程序。安全

1.包和包體的定義
a.包定義
    create or replace package p_stu
    as
        --定義結構體
        type re_stu is record(
            rname student.name%type,
            rage  student.age%type
        );
        --定義遊標
        type c_stu is ref cursor;
        --定義函數
        function numAdd(num1 number,num2 number)return number;
        --定義過程
        procedure GetStuList(cid in varchar2,c_st out c_stu); 
    end;
b.包體實現
    --實現包體,名稱一致。
    create or replace package body p_stu
    as
        --遊標和結構體,包規範中已聲明,包體中不用再聲明,直接使用。
        --實現方法   
        function numAdd(num1 number,num2 number)return number
        as
            num number;
        begin
            num:=num1+num2;
            return num;
        end;        
        --實現過程
        procedure GetStuList(cid varchar2,c_st out c_stu)
        as
            r_stu re_stu; --直接使用包規範中的結構
        begin
            open c_st for select name,age from student where classid=cid;
           -- 若是已經在過程當中遍歷了遊標,在使用這個過程的塊中,將沒有值。
           -- loop
           --     fetch c_st into r_stu;  
           --     exit when c_st%notfound;
           --     dbms_output.put_line('姓名='||r_stu.rname);
           -- end loop;
        end;
    end;
c.使用包
    declare
        c_stu p_stu.c_stu;   --定義包中游標變量
        r_stu p_stu.re_stu;  --定義包中結構體變量
        num number;
    begin
        --使用及遍歷包中過程返回的結果集
        p_stu.GetStuList('C001',c_stu);
        loop
            fetch c_stu into r_stu;
            exit when c_stu%notfound;
            dbms_output.put_line('姓名='||r_stu.rname);
        end loop;       
        --使用包中的方法
        select p_stu.numAdd(5,6) into num from dual;
        dbms_output.put_line('Num='||num);
    end;
d.包的私有過程和函數:沒有在包定義過程聲明,只在包體中定義,只能在包體中相互引用,在包外引用會報
錯‘00302必須聲明…..’也不能用desc命令展現結構包中聲明,可是在包體中沒有具體定義,編譯也會報錯‘00323’服務器

5、PL/SQL動態sql使用
1.靜態SQLSQL與動態SQL 
    前期聯編(early binding),即SQL語句在程序編譯期間就已經肯定,大多數的編譯狀況屬於這種類型,靜態SQL採用;
    後期聯編(late binding),即SQL語句只有在運行階段才能創建,動態SQL採用;
2.EXECUTE IMMEDIATE它解析並立刻執行動態的SQL語句或非運行時建立的PL/SQL塊.動態建立和執行SQL語句性能。語法
Excute immediate 動態SQL語句 using 綁定參數列表 returning into 輸出參數列表
    
3.使用事例
a.在PL/SQL運行DDL語句
    begin
        execute immediate 'set role all';
    end;
b.給動態語句傳值(USING 子句)
    declare
        l_depnam varchar2(20) := 'testing';
        l_loc    varchar2(10) := 'Dubai';
    begin
    execute immediate 'insert into dept values  (:1, :2, :3)'
       using 50, l_depnam, l_loc;
    commit;
    end;
c.傳遞並檢索值.INTO子句用在USING子句前
    declare
        l_dept    pls_integer := 20;
        l_nam     varchar2(20);
        l_loc     varchar2(20);
    begin
        execute immediate 'select dname, loc from dept where deptno = :1'
        into l_nam, l_loc
        using l_dept ;
    end;
d.forall批聯編譯
    declare 
        type num_list is varray(20) of number; 
        v_id num_list :=num_list(100,101); 
    begin 
        ... 
        forall i in v_id.first .. v_id.last loop 
        ... 
        execute immediate 'update emp  set =salary*1.2 
        where id=:1 ' 
        using v_id(i); 
    end loop; 
    end; 模塊化

相關文章
相關標籤/搜索