oracle存储过程

文章转载于: 明将军博客  

存储过程语法结构

create or replace procedure test() is
begin
    null;
end test;

 

存储过程创建语法:

create or repalce procedure 存储过程名(param1 in type,param2 out type)
as
变量1 类型(值范围);
变量2 类型(值范围);
Begin
  select count(*) into 变量1 from 表A where 列名=param1;
    if(判断条件) then
      select 列名 into 变量2 from 表A where列名=param1;
      Dbms_output.Put_line(‘打印信息’);
    elsif(判断条件)then
      Dbms_output.Put_line(‘打印信息’);
    else
      raise 异常名‘数据异常’;
    endif;
  exception
    when others then
      rollback;
End;

注意事项:

1、存储过程参数不带取值范围,in表示传入,out表示输出,类型可以使用任意oracle中的合法类型。

2、 变量带取值范围,后面接分号

3、在判断语句前最好先用count(*)函数判断是否存在该条操作记录

4、用select...into...给变量赋值

5、 在代码中抛异常用 raise+异常名

create or replace procedure 存储过程名(is_ym in char(5),the_count out number)
as
--定义变量名
vs_msg varchar2(1000); --错误信息变量
vs_ym_beg char(6); --起始月份
vs_ym_end char(6); --终止月份
vs_ym_sn_beg char(6); --同期起始月份
vs_ym_sn_end char(6); --同期终止月份
--定义游标,一个可以遍历的结果集
cursor cur_1 is
  select * from ... where ... group by ... order by ...
begin
--用输入参数给变量赋初始值
vs_ym_beg :substr(is_ym,1,6);
vs_ym_end :substr(is_ym,7,6);
vs_ym_sn_beg :to_char(add_month(to_date(is_ym_sn_beg,'yyyymm'),-12),'yyyymm');
vs_ym_sn_end :to_char(add_month(to_date(is_ym_sn_end,'yyyymm'),-12),'yyyymm');
--先删除表中特定的数据
delete from 表名 where ym=is_ym;
--用dbms_output的putline方法打印出结果,其中用到一个系统变量SQL%rowcount
dbms_output.putline('del上月记录数='||SQL%rowcount||'条');
insert into 表名(area_code,ym,cmcode,rmb_amt,usd_amt)select area_code,is_ym,cmcode,sum(rmb_amt)/10000,sum(usd_amt)/10000
from bgd_area_cm_base_t where ym>=vs_ym_beg and ym<=vs_ym_end group by area_code,cmcode;
dbms_output.put_line('ins当月记录数='||SQL%rowcount||'条');
--遍历游标处理后更新到表,遍历游标有多种方法,用户for语句是比较直观的一种
For rec in cur_1 Loop
  update 表名 set rmb_amt_sn=rec.rmb_amt_sn,usd_amt_sn=rec.usd_amt_sn where area_code=rec.area_code and cmcode=rec.cmcode and ym=is_ym
End Loop;
COMMIT;
--错误处理部分,others表示除了声明外的任意错误,sqlerrm是系统内置变量保存了当前错误的详细信息
Exception
  when others then
    vs_msg :='error in xxxxxxx_p('||is_ym||'):'||substr(sqlerrm,1,500);
    rollback;
--把当前错误记录到日志表
  insert into log_info(proc_name,error_info,op_date)values(xxxxxxx_p,vs_msg,sysdate);
  commit;
  return;

end;

 

oracle存储过程语法

1 、判断语句

if 比较式 then begin end; end if; 

create or replace procedure test(x in number) is
begin
  if x>0 then
    begin
      x :=0-x;
    end
  if x=0 then
    begin
      x :=1;
    end;
  endif;
end test;

2 、For 循环 

for ... in ... loop 

-- 执行语句 

end loop; 

1.循环遍历游标
create or replace procedure test() as
cursor cur is selec name from student;
name varchar(20);
begin
  for name in cur loop
  begin
     dbms_output.putline(name);
  end;
  end loop;
end test;

2.循环遍历数组
create or replace procedure test(array in myPackage.testArray) as
--输入参数array是自定义的数组类型
i number;
begin
  i :=1;
  --存储过程数组起始位置从1开始,与java、C++等语言不通,在oracle中是没有数组概念的,数组就是一张表
  --表,每个数组元素就是表中的一个记录,所以遍历数组时就相当于从表的第一条记录开始遍历
  for i in 1..array.count loop
    dbms_output.putline('the No.'||i||'record in array is'||'array(i)');
  end loop;
end test;  

3 、While 循环 

while 条件语句 LOOP 

create or replace procedure test(i in number) as
begin
  while i<10 loop
  begin
    i :=i+1;
  end;
  end loop;
end test;

4 、数组 

首先明确一个概念:Oracle 中本是没有数组的概念的,数组其实就是一张表, 每个数组元素就是表中的一个记录。 

使用数组时,用户可以使用Oracle 已经定义好的数据类型,也可根据自己的需要定义数据类型。 

1.使用oracle自带的数组类型
creaate or replace procedure test(y out array) is
x array;--x需要初始化
begin
  x :=new array();
  y :=x;
end test;
2.自定义数据类型
--自定义数据类型时,一般通过创建package的方式实现,以便于管理
create or replace package myPackage is
  public type declarations type info is record(name varchar(20),y number);
  type testArray is table of info index by bianry_integer;
--此处声明了一个testArray的数据类型,其为一张存储info数据类型的table而已,即testArray就是一张表,有两个值,一个是name,一个是y
--此处使用了index by binary_integer编制该table的索引项,也可不写;若不写,使用数组时就需要进行初始化:
array myPackage.testArray;
array :=new myPackage.testArray();
end testArray;

5. 游标的使用

 Oracle Cursor 是非常有用的,用于遍历临时表中的查询结果。其相关方法和属性也很多,现仅就常用的用法做简单介绍: 

1.cursor型游标(不能用于参数传递)
create or repalce procedure test() is
  cursor cur1 is select std_name from student where ...;
begin
  select class_name into cur2 from class where...;
  for x in cur1
end test;
2.sys_refcursor型游标,该游标是Oracle预先定义的游标,可作出参数进行传递
create or replace procedure test(reCursor out sys_refcursor) is
cursor sys_refcursor;
name varchar(20);
begin
  open cursor for select name from from student where ...
--sys_refcursor只能通过open方法来打开和赋值
  loop
  fetch cursor into name
--sys_refcursor只能通过fetch into 来打开和遍历
  exit when cursor%notfound;
--%rowcount(当前游标所指向的行位置)
  dbms_output.putline(name);
  end loop;
  rsCursor :cursor;
end test;

 

实例

下面写一个简单的例子来对以上所说的存储过程的用法做一个应用: 

现假设存在两张表,一张是学生成绩表(studnet) ,字段为:stdId,math,article,language,music,sport,total,average,step  。一张是学生课外成绩表(out_school), 字段为:stdId,parctice,comment 

通过存储过程自动计算出每位学生的总成绩和平均成绩,同时,如果学生在课外课程中获得的评价为,就在总成绩上加20 分。 

create or replace procedure autocomputer(step in number) is 

rsCursor SYS_REFCURSOR; 

commentArray myPackage.myArray; 

math number; 

article number; 

language number; 

music number; 

sport number; 

total number; 

average number; 

stdId varchar(30); 

record myPackage.stdInfo; 

i number; 

begin 

i := 1; 

get_comment(commentArray); -- 调用名为get_comment() 的存储过程获取学生课外评分信息 

OPEN rsCursor for select stdId,math,article,language,music,sport from student t where t.step = step; 

LOOP 

fetch rsCursor into stdId,math,article,language,music,sport; exit when rsCursor%NOTFOUND; 

total := math + article + language + music + sport; 

for i in 1..commentArray.count LOOP  

 record := commentArray(i);     

if stdId = record.stdId then   

 begin      

 if record.comment = 'A' then      

  begin          

 total := total + 20;    

   go to next; -- 使用go to 跳出for 循环        

  end;     

end if;   

end;   

end if; 

end LOOP; 

<<continue>>  average := total / 5; 

 update student t set t.total=total and t.average = average where t.stdId = stdId; 

end LOOP; 

end; 

end autocomputer; 

-- 取得学生评论信息的存储过程 

create or replace procedure get_comment(commentArray out myPackage.myArray) is 

rs SYS_REFCURSOR ; 

record myPackage.stdInfo; 

stdId varchar(30); 

comment varchar(1); 

i number; 

begin 

open rs for select stdId,comment from out_school 

i := 1; 

LOOP 

 fetch rs into stdId,comment; exit when rs%NOTFOUND; 

record.stdId := stdId; 

 record.comment := comment; 

recommentArray(i) := record; 

i:=i + 1; 

end LOOP; 

end get_comment; 

-- 定义数组类型myArray 

create or replace package myPackage is begin 

type stdInfo is record(stdId varchar(30),comment varchar(1)); 

type myArray is table of stdInfo index by binary_integer; 

end myPackage;

 

posted @ 2019-01-29 18:55  历史为鉴  阅读(188)  评论(0)    收藏  举报