Oracle 存儲過程(procedure)和函數(Function)小結
1、Oracle 存儲過程(procedure)和函數(Function)的區別
-
返回值的區別:函數有1個返回值,一般情況下是用來計算並返回一個計算結果;
而存儲過程是通過參數返回的,可以有多個或者沒有
-
調用的區別 :函數可以在Sql查詢語句中直接調用;
而存儲過程必須單獨調用,一般是用來完成特定的數據操作
(比如修改、插入數據庫表或執行某些DDL語句等等)
-
存儲過程一般是作爲一個獨立的部分來執行( EXECUTE 語句執行);
而函數可以作爲查詢語句的一個部分來調用(SELECT調用),由於函數可以返回一個表對象,
因此它可以在查詢語句中位於FROM關鍵字的後面。 SQL語句中不可用存儲過程,而可以使用函數。
2、在Oracle的函數中,返回表對象
2.1、創建表對象類型
在Oracle中想要返回表對象,必須自定義一個表類型,如下所示:
create or replace type t_table is table of number;
上面的類型定義好後,在function使用可用返回一列的表,如果需要多列的話,需要先定義一個對象類型。
然後把對象類型替換上面語句中的number;
定義對象類型:
create or replace type obj_table as object
(
id int,
name varchar2(50)
);
修改表對象類型的定義語句如下:
create or replace type t_table is table of obj_table;
2.2、創建演示函數
在函數的定義中,可以使用管道化表函數和普通的方式,下面提供兩種使用方式的代碼:
2.2.1、管道化表函數方式
create or replace function f_pipe(s number)
return t_table pipelined
as
v_obj_table obj_table;
begin
for i in 1..s loop
v_obj_table := obj_table(i,to_char(i*i));
pipe row(v_obj_table);
end loop;
return;
end f_pipe;
注意:管道的方式必須使用空的return表示結束。
調用函數的方式如下:
select * from table(f_pipe(5));
2.2.2、普通的方式
create or replace function f_normal(s number)
return t_table
as
rs t_table:= t_table();
begin
for i in 1..s loop
rs.extend;
rs(rs.count) := obj_table(rs.count,'name'||to_char(rs.count));
--rs(rs.count).name := rs(rs.count).name || 'xxxx';
end loop;
return rs;
end f_normal;
調用方式同上
3、oracle複雜自定義函數寫法與實例
3.1、Oracle自定義函數的語法如下
create or replace function 函數名(參數1 模式 參數類型)
return 返回值類型
as
變量1 變量類型;
變量2 變量類型;
begin
函數體;
end 函數名;
參數的模式有3種:(如果沒有註明, 參數默認的類型爲 in.)
in: 爲只讀模式, 在函數中, 參數的值只能被引用, 不能被改變;
out: 爲只寫模式, 只能被賦值, 不能被引用;
in out: 可讀可寫.
提醒:
- 在Oracle自定義函數中, else if 的正確寫法是 elsif 而不是 else if
- 使用 if 需要加 then “if 條件 then 操作”
3.2、簡單例子: 讀入兩個值, 返回比較大的值
create or replace function function1(para1 in number, para2 in number)
return number
as
begin
if para1 > para2 then
return para1;
else
return para2;
end if;
end function1;
select function1(666, 333) from dual;
result:
666
3.3、較複雜實際中會用到的例子(值得把玩)
場景說明:
有時候我們需要按非自然月進行數據統計, 這種時候我們只需要寫一個自定義的函數處理日期就行了.
函數說明: 讀入date型日期,大於15號的歸入下一個月,小於等於15號歸入本月
create or replace function fn_mymonth(oridate in date)
return varchar2
as
oriday number;
orimonth number;
oriyear number;
begin
oriday := to_number(to_char(oridate, 'dd'));
orimonth := to_number(to_char(oridate, 'mm'));
oriyear := to_number(to_char(oridate, 'yyyy'));
if oriday <= 15 then --少於等於15號屬於本月
return to_char(oridate, 'yyyymm');
else
if orimonth <= 8 then -- 月 <=8 則+1後轉char還要補0,單獨出來作爲一種情況
return to_char(oriyear)||'0'||to_char(orimonth + 1);
elsif( orimonth <= 11 ) then -- 月 <= 11則+1後不會跨年,轉char不需要補零, 單獨出來作爲一種情況
return to_char(oriyear)||to_char(orimonth + 1);
else -- 最後一種情況就是跨年, 改變年份, 月份補零就行
return to_char(oriyear + 1)||'0'||to_char(orimonth - 11);
end if;
end if;
end fn_mymonth;
select fn_mymonth(to_date('2015-12-14', 'yyyy-mm-dd')) from dual;
result: 201512
select fn_mymonth(to_date('2015-12-15', 'yyyy-mm-dd')) from dual;
result: 201512
select fn_mymonth(to_date('2015-12-16', 'yyyy-mm-dd')) from dual;
result: 201601
select fn_mymonth(to_date('2015-08-16', 'yyyy-mm-dd')) from dual;
result: 201509
select fn_mymonth(to_date('2015-11-16', 'yyyy-mm-dd')) from dual;
result: 201512