PL-SQL 存儲函數和存儲過程sql
ORACLE 提供可以把PL/SQL 程序存儲在數據庫中,並可以在不論什麼地方來執行它。這樣就叫存儲過程或函數。數據庫
過程和函數統稱爲PL/SQL子程序。他們是被命名的PL/SQL塊,均存儲在數據庫中,並經過輸入、輸出參數或輸入/輸出參數與其調用者交換信息。函數
過程和函數的惟一差異是函數總向調用者返回數據,而過程則不返回數據。oop
①建立函數
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。ui
3) 因爲函數需要返回一個值, 因此RETURN 包括返回結果的數據類型.指針
2. 內嵌函數的調用
函數聲明時所定義的參數稱爲形式參數,應用程序調用時爲函數傳遞的參數稱爲實際參數。應用程序在調用函數時。
可以使用下面三種方法向函數傳遞參數:
第一種參數傳遞格式稱爲位置表示法,格式爲:對象
另一種參數傳遞格式稱爲名稱表示法,格式爲:
argument => parameter [,…]
當中:argument 爲形式參數,它必須與函數定義時所聲明的形式參數名稱一樣。Parameter 爲實際參數。內存
在這樣的格式中,形勢參數與實際參數成對出現,相互間關係惟一肯定,因此參數的順序可以隨意排列。字符串
第三種參數傳遞格式稱爲混合表示法:
即在調用一個函數時,同一時候使用位置表示法和名稱表示法爲函數傳遞參數。採用這樣的參數傳遞方法時,
使用位置表示法所傳遞的參數必須放在名稱表示法所傳遞的參數前面。也就是說。無論函數具備多少個參數,
僅僅要當中有一個參數使用名稱表示法。其後所有的參數都必須使用名稱表示法。io
無論採用哪種參數傳遞方法,實際參數和形式參數之間的數據傳遞僅僅有兩種方法:傳址法和傳值法。
所謂傳址法是指在調用函數時。將實際參數的地址指針傳遞給形式參數,使形式參數和實際參數指向內存中的同一區域。從而實現參數數據的傳遞。
這樣的方法又稱做參照法,即形式參數參照實際參數數據。
輸入參數均採用傳址法傳遞數據。
傳值法是指將實際參數的數據複製到形式參數,而不是傳遞實際參數的地址。默認時,輸出參數和輸入/輸出參數均採用傳值法。
在函數調用時,ORACLE將實際參數數據複製到輸入/輸出參數,而當函數正常執行退出時,又將輸出形式參數和輸入/輸出形式參數數據複製到實際參數變量中。
3. 參數默認值
在CREATE OR REPLACE FUNCTION 語句中聲明函數參數時可以使用DEFAULTkeyword爲輸入參數指定默認值。
具備默認值的函數建立後。在函數調用時,假設沒有爲具備默認值的參數提供實際參數值,函數將使用該參數的默認值。
但當調用者爲默認參數提供實際參數時,函數將使用實際參數值。
在建立函數時,僅僅能爲輸入參數設置默認值,而不能爲輸入/輸出參數設置默認值。
②建立過程
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;