PL-SQL 儲存函數和預存程序,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;