PL-SQL 存儲函數和存儲過程



PL-SQL 存儲函數和存儲過程

ORACLE 提供可以把PL/SQL 程序存儲在數據庫中,並可以在任何地方來運行它。這樣就叫存儲過程或函數。
過程和函數統稱爲PL/SQL子程序,他們是被命名的PL/SQL塊,均存儲在數據庫中,並通過輸入、輸出參數或輸入/輸出參數與其調用者交換信息。
過程和函數的唯一區別是函數總向調用者返回數據,而過程則不返回數據。

①創建函數
1. 建立內嵌函數
語法如下:
CREATE[OR REPLACE] FUNCTION function_name
    [ (argment [ { IN| IN OUT }] Type,
    argment [ { IN| OUT| IN OUT} ] Type ]
    [ AUTHID DEFINER| CURRENT_USER ]
    RETURN return_type
{ IS| AS}
    <類型.變量的說明>
BEGIN
    FUNCTION_body
EXCEPTION
    其它語句
END;
說明:
1) OR REPLACE 爲可選. 有了它, 可以或者創建一個新函數或者替換相同名字的函數, 而不會出現衝突
2) 函數名後面是一個可選的參數列表, 其中包含IN, OUT 或IN OUT 標記. 參數之間用逗號隔開.
    IN 參數標記表示傳遞給函數的值在該函數執行中不改變;
    OUT 標記表示一個值在函數中進行計算並通過該參數傳遞給調用語句;
    IN OUT 標記表示傳遞給函數的值可以變化並傳遞給調用語句. 若省略標記, 則參數隱含爲IN。
3) 因爲函數需要返回一個值, 所以RETURN 包含返回結果的數據類型.

2. 內嵌函數的調用
函數聲明時所定義的參數稱爲形式參數,應用程序調用時爲函數傳遞的參數稱爲實際參數。應用程序在調用函數時,
可以使用以下三種方法向函數傳遞參數:
第一種參數傳遞格式稱爲位置表示法,格式爲:

第二種參數傳遞格式稱爲名稱表示法,格式爲:
argument => parameter [,…]
其中:argument 爲形式參數,它必須與函數定義時所聲明的形式參數名稱相同。Parameter 爲實際參數。
在這種格式中,形勢參數與實際參數成對出現,相互間關係唯一確定,所以參數的順序可以任意排列。

第三種參數傳遞格式稱爲混合表示法:
即在調用一個函數時,同時使用位置表示法和名稱表示法爲函數傳遞參數。採用這種參數傳遞方法時,
使用位置表示法所傳遞的參數必須放在名稱表示法所傳遞的參數前面。也就是說,無論函數具有多少個參數,
只要其中有一個參數使用名稱表示法,其後所有的參數都必須使用名稱表示法。

無論採用哪一種參數傳遞方法,實際參數和形式參數之間的數據傳遞只有兩種方法:傳址法和傳值法。
所謂傳址法是指在調用函數時,將實際參數的地址指針傳遞給形式參數,使形式參數和實際參數指向內存中的同一區域,從而實現參數數據的傳遞。
這種方法又稱作參照法,即形式參數參照實際參數數據。輸入參數均採用傳址法傳遞數據。
傳值法是指將實際參數的數據拷貝到形式參數,而不是傳遞實際參數的地址。默認時,輸出參數和輸入/輸出參數均採用傳值法。
在函數調用時,ORACLE將實際參數數據拷貝到輸入/輸出參數,而當函數正常運行退出時,又將輸出形式參數和輸入/輸出形式參數數據拷貝到實際參數變量中。

3. 參數默認值
在CREATE OR REPLACE FUNCTION 語句中聲明函數參數時可以使用DEFAULT關鍵字爲輸入參數指定默認值。
具有默認值的函數創建後,在函數調用時,如果沒有爲具有默認值的參數提供實際參數值,函數將使用該參數的默認值。
但當調用者爲默認參數提供實際參數時,函數將使用實際參數值。
在創建函數時,只能爲輸入參數設置默認值,而不能爲輸入/輸出參數設置默認值。

②創建過程
1.建立存儲過程
在ORACLE SERVER上建立存儲過程,可以被多個應用程序調用,可以向存儲過程傳遞參數,也可以向存儲過程傳回參數.
創建過程語法:
CREATE[OR REPLACE] PROCEDURE Procedure_name
    [ (argment [ { IN| IN OUT }] Type,
    argment [ { IN| OUT| IN OUT} ] Type ]
    [ AUTHID DEFINER| CURRENT_USER ]
{ IS| AS}
    <類型.變量的說明>
BEGIN
    <執行部分>
EXCEPTION
    <可選的異常錯誤處理程序>
END;

2. 調用存儲過程
ORACLE 使用EXECUTE語句來實現對存儲過程的調用:
EXEC[UTE]  Procedure_name( parameter1, parameter2…);

3.AUTHID
在創建存儲過程時, 可使用AUTHID CURRENT_USER 或AUTHID DEFINER 選項,以表明在執行該過程時Oracle 使用的權限.
1) 如果使用AUTHID CURRENT_USER 選項創建一個過程, 則Oracle 用調用該過程的用戶權限執行該過程.
爲了成功執行該過程,調用者必須具有訪問該存儲過程體中引用的所有數據庫對象所必須的權限

2) 如果用默認的AUTHID DEFINER 選項創建過程, 則Oracle 使用過程所有者的特權執行該過程.爲了成功執行該過程,
過程的所有者必須具有訪問該存儲過程體中引用的所有數據庫對象所必須的權限. 想要簡化應用程序用戶的特權管理,
在創建存儲過程時, 一般選擇AUTHID DEFINER 選項–--這樣就不必授權給需要調用的此過程的所有用戶了.

④刪除存儲過程和存儲函數
1.刪除過程
可以使用DROP PROCEDURE命令對不需要的過程進行刪除,語法如下:
DROP PROCEDURE [user.]Procudure_name;
2.刪除函數
可以使用DROP FUNCTION 命令對不需要的函數進行刪除,語法如下:
DROP FUNCTION [user.]Function_name;

⑤例子
[存儲函數:有返回值,創建完成後,通過select function() from dual;執行]
[存儲過程:由於沒有返回值,創建完成後,不能使用select語句,只能使用pl/sql塊執行]

[格式]
--函數的聲明(有參數的寫在小括號裏)
create or replace function func_name(v_param varchar2)
 --返回值類型
 return varchar2
is
 --PL/SQL塊變量、記錄類型、遊標的聲明(類似於前面的declare的部分)
begin
 --函數體(可以實現增刪改查等操作,返回值需要return)
       return 'helloworld'|| v_logo;
end;

1 函數的 helloworld: 返回一個 "helloworld" 的字符串

create or replace function hello_func
return varchar2
is
begin
       return 'helloworld';
end;

執行函數

begin
    dbms_output.put_line(hello_func());
end;

或者: select hello_func() from dual;

2 返回一個"helloworld: atguigu"的字符串,其中atguigu 由執行函數時輸入。

--函數的聲明(有參數的寫在小括號裏)
create or replace function hello_func(v_logo varchar2)
--返回值類型
return varchar2
is
--PL/SQL塊變量的聲明
begin
--函數體
       return 'helloworld'|| v_logo;
end;

3 創建一個存儲函數,返回當前的系統時間
create or replace function func1
return date
is
--定義變量
v_date date;
begin
 --函數體
 --v_date := sysdate;
       select sysdate into v_date from dual;
       dbms_output.put_line('我是函數哦');
      
       return v_date;
end;

執行法1:
select func1 from dual;
執行法2:
declare
  v_date date;
begin
  v_date := func1;
  dbms_output.put_line(v_date);
end;
4. 定義帶參數的函數: 兩個數相加

create or replace function add_func(a number, b number)
return number
is
begin
       return (a + b);
end;

執行函數

begin
    dbms_output.put_line(add_func(12, 13));
end;
或者
    select add_func(12,13) from dual;

5. 定義一個函數: 獲取給定部門的工資總和, 要求:部門號定義爲參數, 工資總額定義爲返回值.

create or replace function sum_sal(dept_id number)
       return number
       is
      
       cursor sal_cursor is select salary from employees where department_id = dept_id;
       v_sum_sal number(8) := 0;  
begin
       for c in sal_cursor loop
           v_sum_sal := v_sum_sal + c.salary;
       end loop;      

       --dbms_output.put_line('sum salary: ' || v_sum_sal);
       return v_sum_sal;
end;

執行函數

begin
    dbms_output.put_line(sum_sal(80));
end;

6. 關於 OUT 型的參數: 因爲函數只能有一個返回值, PL/SQL 程序可以通過 OUT 型的參數實現有多個返回值

要求: 定義一個函數: 獲取給定部門的工資總和 和 該部門的員工總數(定義爲 OUT 類型的參數).
要求: 部門號定義爲參數, 工資總額定義爲返回值.

create or replace function sum_sal(dept_id number, total_count out number)
       return number
       is
      
       cursor sal_cursor is select salary from employees where department_id = dept_id;
       v_sum_sal number(8) := 0;  
begin
       total_count := 0;

       for c in sal_cursor loop
           v_sum_sal := v_sum_sal + c.salary;
           total_count := total_count + 1;
       end loop;      

       --dbms_output.put_line('sum salary: ' || v_sum_sal);
       return v_sum_sal;
end;  

執行函數:

delare
  v_total number(3) := 0;

begin
    dbms_output.put_line(sum_sal(80, v_total));
    dbms_output.put_line(v_total);
end;

7*. 定義一個存儲過程: 獲取給定部門的工資總和(通過 out 參數), 要求:部門號和工資總額定義爲參數

create or replace procedure sum_sal_procedure(dept_id number, v_sum_sal out number)
       is
      
       cursor sal_cursor is select salary from employees where department_id = dept_id;
begin
       v_sum_sal := 0;
      
       for c in sal_cursor loop
           --dbms_output.put_line(c.salary);
           v_sum_sal := v_sum_sal + c.salary;
       end loop;      

       dbms_output.put_line('sum salary: ' || v_sum_sal);
end;
[執行]
declare
     v_sum_sal number(10) := 0;
begin
     sum_sal_procedure(80,v_sum_sal);
end;

8*. 自定義一個存儲過程完成以下操作:
對給定部門(作爲輸入參數)的員工進行加薪操作, 若其到公司的時間在 (? , 95) 期間,    爲其加薪 %5
                                                               [95 , 98)             %3      
                                                               [98, ?)               %1
得到以下返回結果: 爲此次加薪公司每月需要額外付出多少成本(定義一個 OUT 型的輸出參數).

create or replace procedure add_sal_procedure(dept_id number, temp out number)

is

       cursor sal_cursor is select employee_id id, hire_date hd, salary sal from employees where department_id = dept_id;
       a number(4, 2) := 0;
begin
       temp := 0;      

       for c in sal_cursor loop
           a := 0;   
      
           if c.hd < to_date('1995-1-1', 'yyyy-mm-dd') then
              a := 0.05;
           elsif c.hd < to_date('1998-1-1', 'yyyy-mm-dd') then
              a := 0.03;
           else
              a := 0.01;
           end if;
          
           temp := temp + c.sal * a;
           update employees set salary = salary * (1 + a) where employee_id = c.id;
       end loop;      
end;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章