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