您的位置:首页 > 数据库 > Oracle

关于存储过程和游标的总结

2015-12-23 13:48 525 查看

这两天修改代码的时候,用到了存储过程和游标。这里我就在网上的资料进行汇总一下。供以后使用。

一:首先是游标的使用,下面是摘抄网上的一位朋友,写的很详细,再次表示感谢

Oracle系列:Cursor

1,什么是游标?

 ①从表中检索出结果集,从中每次指向一条记录进行交互的机制。

   

 ②关系数据库中的操作是在完整的行集合上执行的。

  由 SELECT 语句返回的行集合包括满足该语句的 WHERE 子句所列条件的所有行。由该语句返回完整的行集合叫做结果集。

     应用程序,尤其是互动和在线应用程序,把完整的结果集作为一个单元处理并不总是有效的。

     这些应用程序需要一种机制来一次处理一行或连续的几行。而游标是对提供这一机制的结果集的扩展。

     游标是通过游标库来实现的。游标库是常常作为数据库系统或数据访问 API 的一部分而得以实现的软件,

     用来管理从数据源返回的数据的属性(结果集)。这些属性包括并发管理、在结果集中的位置、返回的行数,

     以及是否能够在结果集中向前和/或向后移动(可滚动性)。

     游标跟踪结果集中的位置,并允许对结果集逐行执行多个操作,在这个过程中可能返回至原始表,也可能不返回至原始表。

     换句话说,游标从概念上讲基于数据库的表返回结果集。

     由于它指示结果集中的当前位置 ,就像计算机屏幕上的光标指示当前位置一样,“游标”由此得名。

2,游标有什么作用?

 ①指定结果集中特定行的位置。

 ②基于当前的结果集位置检索一行或连续的几行。

 ③在结果集的当前位置修改行中的数据。

 ④对其他用户所做的数据更改定义不同的敏感性级别。

        ⑤可以以编程的方式访问数据库。

    

3,为什么避免使用游标?

 ①在创建游标时,最需要考虑的事情是,“是否有办法避免使用游标?”

  因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;

  如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。

4,Oracle游标的类型?

 ①静态游标:结果集已经确实(静态定义)的游标。分为隐式和显示游标。

  ⑴隐式游标:所有DML语句为隐式游标,通过隐式游标属性可以获取SQL语句信息。

  ⑵显示游标:用户显示声明的游标,即指定结果集。当查询返回结果超过一行时,就需要一个显式游标。

 ②REF游标:动态关联结果集的临时对象。

 

5,Oracle游标的状态有哪些,怎么使用游标属性?

 ①游标的状态是通过属性来表示。

  %Found :Fetch语句(获取记录)执行情况 True or False。

  %NotFound : 最后一条记录是否提取出 True or False。

  %ISOpen : 游标是否打开True or False。

  %RowCount :游标当前提取的行数 。

 ②使用游标的属性。

  例子:/* conn scott/tiger */

  Begin

   Update emp Set  SAL = SAL + 0.1  Where JOB = 'CLERK';

   If  SQL%Found  Then

    DBMS_OUTPUT.PUT_LINE('已经更新!');

   Else

    DBMS_OUTPUT.PUT_LINE('更新失败!');

   End  If;

  End;

 

6,如何使用显示游标,?如何遍历循环游标?

  ①使用显示游标

   ⑴声明游标:划分存储区域,注意此时并没有执行Select 语句。

    CURSOR 游标名( 参数 列表)   [返回值类型]   IS   Select 语句;

   ⑵打开游标:执行Select 语句,获得结果集存储到游标中,此时游标指向结果集头, 而不是第一条记录。

    Open 游标名( 参数 列表);

   ⑶获取记录:移动游标取一条记录

    Fetch  游标名 InTo  临时记录或属性类型变量;

   ⑷关闭游标:将游标放入缓冲池中,没有完全释放资源。可重新打开。

    Close  游标名;

 ②遍历循环游标

  ⑴For 循环游标

   循环游标隐式打开游标,自动滚动获取一条记录,并自动创建临时记录类型变量存储记录。处理完后自动关闭游标。

     For  变量名  In  游标名 

     Loop

      数据处理语句;

     End Loop;

   ⑵Loop循环游标

     。。。

    Loop

     Fatch  游标名 InTo  临时记录或属性类型变量;

     Exit  When   游标名%NotFound;

    End   Loop;

     。。。

  例子1:

  /* conn scott/tiger */

   Declare

     Cursor myCur is select empno,ename,sal from emp;

     vna varchar2(10);

     vno number(4);

     vsal number(7,2);

  Begin

     open myCur;

     fetch myCur into vno,vna,vsal;

     dbms_output.put_line(vno||'    '||vna||'    '||vsal);

     close myCur;

  End;

  /

 

 例子2:使用loop遍历游标。

 /* conn scott/tiger */

  Declare

     Cursor myCur is select ename,job,sal,empno from emp;

     varE myCur%rowType;

  Begin

     if myCur%isopen = false then

        open myCur;

       dbms_output.put_line('Opening...');

     end if;

     loop

        fetch myCur into varE;

        exit when myCur%notfound;

        dbms_output.put_line(myCur%rowCount||'    '||vare.empno||'    '||vare.ename||'    '||vare.sal);

     end loop;

     if myCur%isopen then

        Close myCur;

        dbms_output.put_line('Closing...');

     end if;

  End;

  /

 

  例子3:使用For循环遍历游标,

  /* conn scott/tiger */

  Declare

     Cursor myCur is select * from emp;

  Begin

     for varA in myCur

      loop

         dbms_output.put_line(myCur%rowCount||'    '||varA.empno||'    '||varA.ename||'  '||varA.sal);

      end loop;

  End;

  /

7,怎样更新和删除显示游标中的记录?

 ①UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据。

  要使用这个方法,在声明游标时必须使用FOR UPDATE子串,当对话使用FOR UPDATE子串打开一个游标时,

  所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,其他对象只能查询这些数据行,

  不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。

   在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,那么所有表中选择的数据行都将被锁定。

   如果这些数据行已经被其他会话锁定,那么正常情况下ORACLE将等待,直到数据行解锁。

 ②使用更新或删除:

  ⑴声明更新或删除显示游标:

   Cursor 游标名 IS  SELECT 语句   For Update [ Of  更新列列名];

   Cursor 游标名 IS  SELECT 语句   For Delete [ Of  更新列列名];

  ⑵使用显示游标当前记录来更新或删除:

   Update  表名   SET  
4000
更新语句  Where   Current  Of   游标名;

   Delete  From  表名   Where   Current  Of   游标名;

 

   例子1:更新显示游标记录

   /*conn scott/tiger*/

   Declare

     Cursor myCur is select job from emp for update;

       vjob empa.job%type;

       rsal empa.sal%type;

    Begin

       open myCur;

       loop

          fetch myCur into vjob;

          exit when myCur%notFound;

          case  (vjob)

             when 'ANALYST' then  rsal := 0.1;

            when  'CLERK' then  rsal := 0.2;

             when  'MANAGER' then  rsal := 0.3;

             else

               rsal := 0.5;

          end case;

        update emp set sal = sal + rsal where current of myCur;

       end loop;

    End;

    /

    例子2:删除显示游标记录

    /*conn scott/tiger

    Crate table  empa  Select * from scott.emp;

    */

    Declare

      Cursor MyCursor  Select   JOB  From  empa  For  Update;

      vSal   emp.Sal%TYPE;

    Begin

      Loop

       Fetch  MyCursor  InTo  vSal;

       Exit  When  MyCursor%NotFound;

       If   vSal < 800 Then

        Delete  From empa  Where  Cursor  Of   MyCursor;

       End  If;  

      End    Loop;

    End;/

8,什么是带参数的显示游标?

 ①与过程和函数相似,可以将参数传递给游标并在查询中使用。

  参数只定义数据类型,没有大小(所有Oracle中的形参只定义数据类型,不指定大小)。

  与过程不同的是,游标只能接受传递的值,而不能返回值。

   可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。

  游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。

 ②使用带参数的显示游标

  ⑴声明带参数的显示游标:

   CURSOR 游标名  [(parameter[,parameter],...)]    IS   Select语句;;

  

   参数形式:1,参数名   数据类型  

       2,参数名   数据类型  DEFAULT  默认值

      

   例子:

    /*conn scott/tiger

    Crate table  empa  Select * from scott.emp;

    */

    Declare

      Cursor MyCursor(pSal  Number  Default   800)  Select   JOB  From  empa Where  SAL >  pSal ;

      varA  MyCursor%ROWTYPE;

    Begin

      Loop

       Fetch  MyCursor  InTo  varA;

       Exit  When  MyCursor%NotFound;

       DBMS_OUTPUT.PUT_LINE(MyCursor%RowCount||'    '||varA.empno||'    '||varA.ename||'  '||varA.sal); 

      End    Loop;

    End;/

==============================================================================

1,什么是 REF游标 ?

 动态关联结果集的临时对象。即在运行的时候动态决定执行查询。

 

2,REF 游标 有什么作用?

 实现在程序间传递结果集的功能,利用REF CURSOR也可以实现BULK SQL,从而提高SQL性能。

3,静态游标和REF 游标的区别是什么?

 ①静态游标是静态定义,REF 游标是动态关联;

 ②使用REF 游标需REF 游标变量。

 ③REF 游标能做为参数进行传递,而静态游标是不可能的。

 

4,什么是REF 游标变量?

 REF游标变量是一种 引用 REF游标类型  的变量,指向动态关联的结果集。

5,怎么使用  REF游标 ?

 ①声明REF 游标类型,确定REF 游标类型;

  ⑴强类型REF游标:指定retrun type,REF 游标变量的类型必须和return type一致。

   语法:Type   REF游标名   IS   Ref Cursor Return  结果集返回记录类型;

  ⑵弱类型REF游标:不指定return type,能和任何类型的CURSOR变量匹配,用于获取任何结果集。

   语法:Type   REF游标名   IS   Ref Cursor;

 ②声明Ref 游标类型变量;

  语法:变量名  已声明Ref 游标类型;

 

 ③打开REF游标,关联结果集 ;

  语法:Open   Ref 游标类型变量   For   查询语句返回结果集;

 

 ④获取记录,操作记录;

  语法:Fatch    REF游标名 InTo   临时记录类型变量或属性类型变量列表;

 

 ⑤关闭游标,完全释放资源;

  语法:Close   REF游标名;

 

 例子:强类型REF游标

 /*conn scott/tiger*/

 Declare

  Type MyRefCurA IS  REF CURSOR RETURN emp%RowType;

  Type MyRefCurB IS  REF CURSOR RETURN emp.ename%Type;

  vRefCurA  MyRefCurA;

  vRefCurB  MyRefCurB;

  vTempA  vRefCurA%RowType;

  vTempB  vRefCurB.ename%Type;

 

 Begin

  Open  vRefCurA  For Select  *  from   emp   Where  SAL > 2000;

  Loop

   Fatch  vRefCurA InTo  vTempA;

   Exit  When  vRefCurA%NotFound;

   DBMS_OUTPUT.PUT_LINE(vRefCurA%RowCount||'  '|| vTempA.eno||'  '||vTempA.ename ||'  '||vTempA.sal)

  End Loop;

  Close vRefCurA;

 

  DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------------------------------------------');

 

  Open  vRefCurB  For Select  ename  from   emp   Where  SAL > 2000;

  Loop

   Fatch  vRefCurB InTo  vTempB;

   Exit  When  vRefCurB%NotFound;

   DBMS_OUTPUT.PUT_LINE(vRefCurB%RowCount||'  '||vTempB)

  End Loop;

  Close vRefCurB;

 

  DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------------------------------------------');  

 

  Open  vRefCurA  For Select  *  from   emp   Where  JOB = 'CLERK';

  Loop

   Fatch  vRefCurA InTo  vTempA;

   Exit  When  vRefCurA%NotFound;

   DBMS_OUTPUT.PUT_LINE(vRefCurA%RowCount||'  '|| vTempA.eno||'  '||vTempA.ename ||'  '||vTempA.sal)

  End Loop;

  Close vRefCurA;

 End;

 

 例子:弱类型REF游标

 /*conn scott/tiger*/

 Declare

  Type MyRefCur  IS  Ref  Cursor;

  vRefCur MyRefCur;

  vtemp  vRefCur%RowType;

 Begin

  Case(&n)

   When  1 Then Open vRefCur  For Select   *   from emp;

   When  2 Then Open vRefCur  For Select   *   from dept;

   Else

    Open vRefCur  For Select   eno,  ename  from emp Where JOB = 'CLERK';

  End Case;

  Close  vRefCur;

 End;

=======================================================================

 9.动态游标就是动态定义游标。下面是一些完整的例子:

 1.  

  declare  

  type   t_sor   is   ref   cursor;  

  v_sor   t_sor;     --必需的,通过对象变量实现.  

  ...  

  begin    

  ..  

  end;  

  /

 

给一个完整的例子:  

  create   or   replace   procedure   SP_CLEAR(V_TABLE   IN   STRING)   IS  

   

      TYPE   cur_type   IS   REF   CURSOR;  

      c_tab   cur_type;  

      v_str   STRING(2000);  

      v_tab   t_clear.wlbmc%TYPE;  

      v_sql   STRING(3000);  

   

   

  begin  

      --Get   table   from   v_table  

      --Reorder   these   tables  

      v_str:=upper(v_table);  

      v_str:=REPLACE(v_str,',',''',''');  

      v_str:=''''||v_str||'''';  

      v_sql:='SELECT   WLBMC   FROM   T_CLEAR   WHERE   TRIM(WLBMC)   IN   ('||v_str||')   ORDER   BY   BZ   DESC';  

      OPEN   c_tab  
FOR   v_sql;  

      LOOP  

          FETCH   c_tab   INTO   v_tab;  

          EXIT   WHEN   c_tab%NOTFOUND;  

          v_sql:='delete   from   '||v_tab||'';  

          EXECUTE   IMMEDIATE   v_sql;      

      END   LOOP;        

      COMMIT;      

      --deal   with   exception    

      EXCEPTION    

          WHEN   OTHERS   THEN  

                ROLLBACK;  

                RAISE;  

  end   SP_CLEAR;  

  /   

 

3.字符串变量带动态参数例子2

给你一个完整的例子:  

  DECLARE  

        TYPE   EmpCurTyp   IS   REF   CURSOR;  

        emp_cv       EmpCurTyp;  

        emp_rec     emp%ROWTYPE;  

        sql_stmt   VARCHAR2(200);  

        my_job       VARCHAR2(15)   :=   'CLERK';  

  BEGIN  

        sql_stmt   :=   'SELECT   *   FROM   emp   WHERE   job   =   :j';  

        OPEN   emp_cv  
FOR   sql_stmt  
USING   my_job;  

        LOOP  

              FETCH   emp_cv   INTO   emp_rec;  

              EXIT   WHEN   emp_cv%NOTFOUND;  

              --   process   record  

        END   LOOP;  

        CLOSE   emp_cv;  

  END;   

4.下面是一个完整的实例:非常好,带有存储过程的动态游标

create or replace procedure DATA_CHECK_SITE(bat_id in varchar2,flag out varchar2)

is

TYPE cur_cursor IS REF CURSOR;                                                                                             

cur       cur_cursor;

                                                                                                         

data_sql  varchar2(1024);

v_key     number;

v_bat_id  varchar2(64);

v_area_id VARCHAR2(5);

sql_del   varchar2(256) := 'truncate table iodso.GXZY_ODS_SITE_temp';

e_err     varchar2(2000) :='';

begin

   data_sql := 'select id,bat_id,area_id from iodso.GXZY_ODS_SITE_temp where bat_id=:bat_id';

   OPEN cur FOR data_sql using bat_id;

    loop

           fetch cur into v_key,v_bat_id,v_area_id;

           exit when cur%notfound;

           declare

             v_count         number(9);

             v_temp_bat_id   varchar2(32);

             v_data_state    varchar2(32);

             sql_count       varchar2(256) := 'select count(*) from odso.GXZY_ODS_SITE where id=:v_key and area_id=:v_area_id';

             sql_insert      varchar2(500) := 'insert into odso.GXZY_ODS_SITE(ID,NAME,CODE,PXJ,PARENT_ID,PARENT_CODE,CREATE_TIME,EDIT_TIME,STATUS,INS_DATE,BAT_ID,AREA_ID)

                                                                       select ID,NAME,CODE,PXJ,PARENT_ID,PARENT_CODE,CREATE_TIME,EDIT_TIME,STATUS,INS_DATE,BAT_ID,AREA_ID

                                                                       from iodso.GXZY_ODS_SITE_temp where id=:v_key and area_id=:v_area_id';

             sql_check_batid varchar2(256) := 'select bat_id,LOWER(status) from odso.GXZY_ODS_SITE where id=:v_key and area_id=:v_area_id and rownum < 2 ' ;

             sql_delete      varchar2(256) := 'delete from odso.GXZY_ODS_SITE where id=:v_key and area_id=:v_area_id';

           begin  

               execute immediate sql_count into v_count using v_key,v_area_id;

               if v_count=0 then

                  --业务表不包含这条数据,直接插入

                  execute immediate sql_insert using v_key,v_area_id;

               else

                  --业务表中包含这条数据,则判断数据批次号

                  execute immediate sql_check_batid into v_temp_bat_id,v_data_state using v_key,v_area_id;

                  if v_temp_bat_id>=v_bat_id then

                     --如果业务数据批次号大于临时批次号,说明临时数据是老的

                     null;

                  else

                     --否则判断数据状态

                     if v_data_state='insert' then

                        --如果是新增,直接插入

                        execute immediate sql_delete using v_key,v_area_id;

                        execute immediate sql_insert using v_key,v_area_id;

                     elsif v_data_state='update' then

                        --如果是修改,先删除老数据,再插入新数据

                        execute immediate sql_delete using v_key,v_area_id;

                        execute immediate sql_insert using v_key,v_area_id;

                     else

                        --删除数据

                        execute immediate sql_delete using v_key,v_area_id;

                     end if;

                  end if;

               end if;  

               null;

           end;

    end loop;

     close cur;

   insert into MSG_INTERFACE_LOG values(sysdate,'1014','空间资源局站信息','success',bat_id);

   commit;

   execute immediate sql_del;

      flag:='true';

   exception when others then

      flag:='false';

      e_err := SQLERRM;

      insert into MSG_INTERFACE_LOG values(sysdate,'1014','空间资源局站信息',e_err,bat_id||'<>'||v_key||'<>'||v_area_id);

      rollback;

      raise;

end DATA_CHECK_SITE;

 

二:下面是存储过程的一些资料。感觉非常的全。所以转载至此

 

1 、创建存储过程

create or replace procedure test(var_name_1 in type,var_name_2 out type) as

-- 声明变量( 变量名 变量类型),用as来代替declare

begin

-- 存储过程的执行体

end test;

打印出输入的时间信息

E.g:

create or replace procedure test(workDate in Date) is

begin

/*打印前必须在pl/sql中设置set serveroutput on;否则不能显示结果

dbms_output.putline('The input date is:'||to_date(workDate,'yyyy-mm-dd'));

end test;

2 、变量赋值

变量名 := 值;

E.g :

create or replace procedure test(workDate in Date) is

x number(4,2);

 begin

 x := 1;

end test;

3 、判断语句:

if 比较式 then begin end; end if;

E.g

create or replace procedure test(x in number) is

begin

        if x >0 then

         begin

        x := 0 - x;

        end;

    end if;

    if x = 0 then

       begin

        x: = 1;

    end;

    end if;

end test;

4 、For
循环

For ... in ... LOOP

-- 执行语句

end LOOP;

(1) 循环遍历游标

create or replace procedure test() as

Cursor cursor is select name from student; name varchar(20);

begin

for name in cursor LOOP

begin

 dbms_output.putline(name); 

end;

end LOOP;

end test;

(2) 循环遍历数组

 create or replace procedure test(varArray in myPackage.TestArray) as

--( 输入参数varArray
是自定义的数组类型,定义方式见标题6)

i number;

begin

i := 1;  -- 存储过程数组是起始位置是从1 开始的,与java 、C 、C++ 等语言不同。因为在Oracle 中本是没有数组的概念的,数组其实就是一张

-- 表(Table), 每个数组元素就是表中的一个记录,所以遍历数组时就相当于从表中的第一条记录开始遍历

for i in 1..varArray.count LOOP     

dbms_output.putline('The No.'|| i || 'record in varArray is:'||varArray(i));   

 end LOOP;

end test;

5 、While
循环

while 条件语句 LOOP

begin

end;

end LOOP;

E.g

create or replace procedure test(i in number) as

begin

while i < 10 LOOP

begin    

 i:= i + 1;

end;

end LOOP;

 end test;

6 、数组

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

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

(1) 使用Oracle 自带的数组类型

x array; -- 使用时需要需要进行初始化

e.g:

create or replace procedure test(y out array) is

 x array;  

 begin

x := new array();

y := x;

end test;

(2) 自定义的数组类型 ( 自定义数据类型时,建议通过创建Package 的方式实现,以便于管理)

E.g ( 自定义使用参见标题4.2)

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 binary_integer;  

-- 此处声明了一个TestArray 的类型数据,其实其为一张存储Info 数据类型的Table 而已,及TestArray
就是一张表,有两个字段,一个是name ,一个是y 。需要注意的是此处使用了Index by binary_integer
编制该Table 的索引项,也可以不写,直接写成:type TestArray is

table of info ,如果不写的话使用数组时就需要进行初始化:varArray myPackage.TestArray; varArray := new myPackage.TestArray();

end TestArray;

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

(1)Cursor 型游标( 不能用于参数传递)

create or replace procedure test() is  

cusor_1 Cursor is select std_name from student where  ...;  --Cursor
的使用方式1   cursor_2 Cursor;

begin

select class_name into cursor_2 from class where ...;  --Cursor
的使用方式2

可使用For x in cursor LOOP .... end LOOP;
来实现对Cursor 的遍历

end test;

(2)SYS_REFCURSOR 型游标,该游标是Oracle 以预先定义的游标,可作出参数进行传递

create or replace procedure test(rsCursor out SYS_REFCURSOR) is

cursor SYS_REFCURSOR; name varhcar(20);

begin

OPEN cursor FOR select name from student where ... --SYS_REFCURSOR
只能通过OPEN 方法来打开和赋值

LOOP

 fetch cursor into name   --SYS_REFCURSOR
只能通过fetch into 来打开和遍历 exit when cursor%NOTFOUND;              --SYS_REFCURSOR 中可使用三个状态属性:                                         ---%NOTFOUND( 未找到记录信息) %FOUND(
找到记录信息)                                         ---%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

通过存储过程自动计算出每位学生的总成绩和平均成绩,同时,如果学生在课外课程中获得的评价为A ,就在总成绩上加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;

原文地址:http://blog.csdn.net/guolimin1118/article/details/4669764
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据库 游标 oracle