加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

游标的使用及%type、%rowtype、function和procedure的一些用法和注意事项

(2015-03-31 14:26:28)
标签:

oracle

sql

分类: 数据库
一、1,显式游标:

显式游标的几个属性:
   %found:测试fetch语句是否有值(数据),有值就返回true,否则为false;

   %notfound:判断游标是否没有数据或有效,没有就true,有等于false.

   %rowcount:返回游标的数据行数|返回当前位置为止游标读取的记录行数;

   %isopen:是测试游标是否打开。如果没有打开游标就使用fetch语句就提示错误;

游标与存储过程和函数相似,可以将对参数传递给游标并在查询中使用,
cursor cursor_name(parameter_name in date_type...) is
select_statement
定义的参数语法如下:
  parameter_name[in]data_type[(:|default)value]
注意与存储过程不同的时,游标只能接受传递的值,而不能返回值。

           参数是定义数据类型,没有大小。

           使用for进行游标循环时,可以不显式地打开和关闭游标----for循环会自动执行这些操作。

           while进行游标循环时,要注意给fetch的放置;

           在使用for循环时,它的变量相当于一个记录型变量,里面存储着此游标所存放的变量!

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


2、变量:

1)使用%type

   在pl/sql中可以将变量和常量声明为内建或用户定义的数据类型,以引用一个列名,同时继承他的数据类型和大小(用于获取列的类型,如果在声明变量的时候使用%type,变量会自动将变量类型设置为列的类型)
  如: 有表prdtest
declare
       v_moth prdtest.month%type;         ----保存prdtype表中moth列
       v_prd_type prdtest.prd_type%type;-----保存prdtype表中prd_type列
       v_sal prdtest.sal%type;                    ----保存prdtype表中sal列
       v_salers prdtest.salers%type;           ----保存prdtype表中salers列

       v_velin number(5):=10;
       v_hweilei v_velin%type:=15;
       v_weile v_velin%type;



       在许多情况下,PL/SQL变量可以用来存储在数据库表中的数据。在这种情况下,变量应该拥有与表列相同的类型。例如,students表的first_name列的类型为VARCHAR2(20),我们可以按照下述方式声明一个变量:

DECLARE

       v_FirstName VARCHAR2(20);

但是如果first_name列的定义改变了会发生什么(比如说表改变了,first_name现在的类型变为VARCHAR2(25))?那就会导致所有使用这个列的PL/SQL代码都必须进行修改。如果你有很多的PL/SQL代码,这种处理可能是十分耗时和容易出错的。

这时,你可以使用”%TYPE”属性而不是将变量类型硬性编码。

例如:

DECLARE

       v_FirstName students.first_name%TYPE;

 

通过使用%TYPE,v_FirstName变量将同students表的first_name列的类型相同(可以理解为将两者邦定起来)。

每次匿名块或命名块运行该语句块以及编译存储对象(过程、函数、包、对象类和触发器)时,就会确定该类型。

使用%TYPE是非常好的编程风格,因为它使得PL/SQL更加灵活,更加适应于对数据库定义的更新。

-------------------------------------------------------------------------------------------------------------------

2. 使用%ROWTYPE

    2.1  PL/SQL记录

PL/SQL记录类型类似于C语言中的结构,是一种复合类型,是用户自定义的。

      记录提供了一种处理独立的但又作为一个整体单元相关的变量的机制。请看:

DECLARE

       v_StudentID NUMBER(5);

       v_FirstName VARCHAR2(20);

       v_LastName VARCHAR2(20);


这3个变量在逻辑上是相互关联的,因为他们指向students表中不同的字段。如果为这些变量声明一个记录类型,那么他们之间的关系就十分明显,可作为一个单元进行处理。

 
DECLARE

      

       TYPE t_StudentRecord IS RECORD(

              StudentID NUMBER(5),

              FirstName VARCHAR2(20),

              LastName VARCHAR2(20);

      

       v_StudentInfo t_StudentRecord;

 

2.2 记录赋值

       可以用SELECT语句向记录赋值,这将会从数据库中检索数据并将该数据存储到记录中。注意的是,记录中字段应该和查询结果列表中的字段相匹配。

SELECT studentID,firstName,lastName

into v_StudentInfo

from students where studentID=32;

 

2.3 使用%ROWTYPE

 

在PL/SQL中将一个记录声明为具有相同类型的数据库行的作法是很常见的。PL/SQL提供了%ROWTYPE运算符,使得这样的操作更为方便。

例如:

DECLARE

       v_RoomRecord rooms%ROWTYPE;

将定义一个记录,该记录中的字段将与rooms表中的列相对应

例 :

Declare
 v_rowtype v%Rowtype;
 Begin
    Select * Into v_rowtype From v Where Id=2;---Declare
 v_rowtype v%Rowtype;
 Begin
    Select * Into v_rowtype From v Where Id=2/;----如果去掉where id=2 则要报错(这里因为%rowtype只能存储一行记录!)
    Dbms_Output.put_line(':'||v_rowtype.id);
 End;

    Dbms_Output.put_line(':'||v_rowtype.id);
 End;
 %ROWTYPE
使用%ROWTYPE属性可以声明一个基于表或游标的行对象,也称为记录对象 ,如以下的例:

declare
 v_rowtype   v%rowtype;
 cursor v_test_cursor is
  select * from v where id=1;
begin
 open v_test_cursor;
 loop
  fetch v_test_cursor
  into v_rowtype;
  dbms_output.put_line('这是:' || v_rowtype.id);
  exit when v_test_cursor%notfound;
 end loop ;
 end;

记录变量
        定义一个记录变量使用TYPE命令和%ROWTYPE,关于%ROWsTYPE的更多信息请参阅相关资料。
        记录变量用于从游标中提取数据行,当游标选择很多列的时候,那么使用记录比为每列声明一个变量要方便得多。
       当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时,如果要选择表中所有列,那么在SELECT子句中使用*比将所有列名列出来要得多。

 

例:
SET SERVERIUTPUT ON
DECLARE
R_emp EMP%ROWTYPE;
CURSOR c_emp IS SELECT * FROM emp;
BEGIN
OPEN c_emp;
  LOOP
  FETCH c_emp INTO r_emp;
  EXIT WHEN c_emp%NOTFOUND;
  DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
  END LOOP;
CLOSE c_emp;
END;

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

显式游标的举例:
       当查询返回结果超过一行时,就需要一个显式游标,此时用户不能使用select into语句。PL/SQL管理隐式游标,当查询开始时隐式游标打开,查询结束时隐式游标自动关闭。显式游标在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取数据,关闭。

   a)声明游标:
         cursor  cursor_name is select_statement;
注:在PL/SQL中游标名是一个未声明变量,不能给游标名赋值或用于表达式中
  例如:
       cursor v_prdtest_cursor is          -----v_prdtest为游标名;
       select month,prd_type ,sal,salers    ----游标内容
       from prdtest order by prd_type;     ---- 游标内容      
   b)打开游标:
         open v_prdtest_cursor ;----打开游标;
   c)关闭游标:
         close v_prdtest_cursor;
   d)从游标中提取数据:
        从游标得到一行数据使用FETCH命令。每一次提取数据后,游标都指向结果集的下一行。语法如下:
    fetch cursor_name into variable[,variable1....]
    如:
    fetch prd_test_cursor into v_month,v_prd_type,v_sal,v_salers;----从游标v_prdtest_cursor中读取一条记录,放入到v_month,v_prd_type,v_sal,v_salers变量中。----在for游标循环里,变量相当于v_month,v_prd_type,v_sql,v_sqlersrn 所存储的记录集类型。
注:
     对于SELECT定义的游标的每一列,FETCH变量列表都应该有一个变量与之相对应,变量的类型也要相同。

   e)带参数的游标

       与存储过程和函数相似,可以将参数传递给游标并在查询中使用。这对于处理在某种条件下打开游标的情况非常有用。它的语法如下:  
       CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;  
定义参数的语法如下:  
       Parameter_name [IN] data_type[{:=|DEFAULT} value]  
与存储过程不同的是,游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。  
      另外可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。

      在打开游标时给参数赋值,语法如下:  
      OPEN cursor_name[value[,value]....];  参数值可以是文字或变量。

    带参数的游标举例:

  Declare
  Cursor c_Emp(p_Id Integer) Is  ----带参数的游标
    Select Id, Names, Sal From v Where Id = p_Id Order By Names;
  v_Id     v.Id%type;
  v_Ename  v.Names%Type;
  v_Salary v.Sal%Type;
Begin
  Open c_Emp(3);----给参数赋值.
  Loop
    Fetch c_Emp
      Into v_id,v_Ename, v_Salary;
    Exit When c_Emp%Notfound;
    Dbms_Output.Put_Line('Name:' || v_Ename || ' salary:' || v_Salary ||'id:'||v_id);
   ---- v_Tot_Salary := v_Tot_Salary + v_Salary;
  End Loop;
  Close c_Emp;
  ----Dbms_Output.Put_Line('Toltal Salary for dept:' || v_Tot_Salary);
End;
 
   c:关闭游标:
     close v_prdtest_cursor
-------------------------------------------------------------------------------------------------------------------
几个简单的例子:

a:for游标的例:

1):

   declare
      v_id        v.id%type;
      v_name      v.name%type;
      v_age       v.age%type;
      v_hweilei_1 v.hweilei_1%type;
      cursor v_test_cursor is
       select * from v;
     begin
      for v_cursor in v_test_cursor loop
      dbms_output.put_line('这是测试游标的作用:' || v_cursor.id || v_cursor.name || v_cursor.age ||v_cursor.hweilei_1);
      end loop;
     end;

2)
Declare
       v_id Integer ;
       v_names Varchar2(10);
       ---Cursor v_test_cursor Is Select *From dual; ----可以定义一个参数,也可以不定义,都是可以的!
       Begin
        For v_test_cursor  In(Select Id,names From v ) Loop
            Dbms_Output.put_line('this is test cursor:'||v_test_cursor.id);
        End Loop ;
       End;

       这就是FOR循环,用于FOR循环的游标按照正常的声明方式声明,它的优点在于不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等

b:while例子:

(1):

      declare v_id  v.id%type;
               v_name v.name%type;
               v_age  v.age%type;
               v_hweilei_1 v.hweilei_1%type;
               cursor v_test_cursor is select  * from v;
               cc v_test_cursor%rowtype;
       begin
       open v_test_cursor;
       fetch v_test_cursor into cc;
       while v_test_cursor%found  loop
       fetch v_test_cursor into cc;
       dbms_output.put_line('这是测试游标的作用:'||cc.id ||cc.name ||cc.age ||cc.hweilei_1|| '这是多少行:'||v_test_cursor%rowcount );
       end loop;    
       close   v_test_cursor;              
       end;
   (2):

          declare v_id  v.id%type;
               v_name v.name%type;
               v_age  v.age%type;
               v_hweilei_1 v.hweilei_1%type;
               cursor v_test_cursor is select  * from v;
               
       begin
       open v_test_cursor;
   fetch v_test_cursor into v_id,v_name,v_age,v_hweilei_1;
       while v_test_cursor%found  loop
       fetch v_test_cursor into v_id,v_name,v_age,v_hweilei_1;
       dbms_output.put_line('这是测试游标的作用:'||v_id ||v_name ||v_age ||v_hweilei_1|| '这是多少行:'||v_test_cursor%rowcount );
       end loop;    
       close   v_test_cursor;              
       end;

c:loop例子:

       declare

     
       v_id        v.id%type;
       v_name      v.name%type;
       v_age       v.age%type;
       v_hweilei_1 v.hweilei_1%type;
       cursor v_test_cursor is
        select * from v;
      begin
       open v_test_cursor;
       loop
        fetch v_test_cursor
        into v_id, v_name, v_age, v_hweilei_1;
        exit when v_test_cursor%notfound;

        
        dbms_output.put_line('这是测试游标的作用:' || v_id || v_name || v_age ||
                             v_hweilei_1 || '这是多少行:' ||
                             v_test_cursor%rowcount);---------当前为止,游标数的个数!

             end loop;
       close v_test_cursor;
      end;

再一个loop例:

Declare

v_rowcoun       Number;
v_id            v.id%Type;
v_names         v.names%Type;
v_work_id       v.Work_Id%Type;
v_mate_work_id  v.Mate_Work_Id%Type;
v_area          v.Area%Type;
v_code_id       v.Code_Id%Type;
Cursor v_vv_cursor Is Select Id  From v ;--定义了一个游标;
Begin
       Open v_vv_cursor ;
       Loop
       Fetch v_vv_cursor Into v_id;----一次只能取一个数,所以执行时,先打印出了id=2;
       Exit When v_vv_cursor %Notfound ; ----利用显式游标的性质进行循环!

       v_rowcoun:=v_vv_cursor%rowcount;   -----当前为止,游标数的个数!
       Dbms_Output.put_line('please printing this is word:'||v_id);

       Dbms_Output.put_line('please printing this is word:'|| v_rowcoun);

       End Loop;
       Close v_vv_cursor;
End;

 可以使用对象 %rowtype,如下:

declare
 v_rowtype   v%rowtype;
 cursor v_test_cursor is
  select * from v where ;-----如果只取全表的某一字段或少于全表字段则报错(id ,name ,age ,hweilei_1);
begin
 open v_test_cursor;
 loop
  fetch v_test_cursor
  into v_rowtype;
  dbms_output.put_line('这是:' || v_rowtype.id);
  exit when v_test_cursor%notfound;
 end loop ;
 end;

注意:此时在定义游标时,须是全表的字段,不能只取其某一个或多个字段,一定是全表字段,否则要报错!

-------------------------------------------------------------------------------------------------------------------

隐式游标:

       当执行一条DML语句后,DML语句的结果保存在四个游标属性中,这些属性用于控制程序流程或者了解程序的状态。当运行DML语句时,PL/SQL打开一个内建游标并处理结果,游标是维护查询结果的内存中的一个区域,游标在运行DML语句时打开,完成后关闭。隐式游标只使用SQL%FOUND,SQL%NOTFOUND,SQL%ROWCOUNT三个属性.SQL%FOUND,SQL%NOTFOUND是布尔值,SQL%ROWCOUNT是整数值。
  SQL%FOUND和SQL%NOTFOUND
  在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性值将是:
  . TRUE :INSERT
  . TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE.
  . TRUE :SELECT INTO至少返回一行
  当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE。
  SQL%ROWCOUNT
  在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT INTO语句,如果执行成功,SQL%ROWCOUNT的值为1,如果没有成功或者没有操作(如update、insert、delete为0条),SQL%ROWCOUNT的值为0.同时产生一个异常NO_DATA_FOUND.
  SQL%ISOPEN
  SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE, 如果游标关闭,则为FALSE.对于隐式游标而言SQL%ISOPEN总是FALSE,这是因为隐式游标在DML语句执行时打开,结束时就立即关闭。

     注:

    if SQL%ROWCOUNT = 0 then这个判断应该放在commit前面,如果执行了commit,SQL%ROWCOUNT 就变回0了,因此应该有一个变量,存储更新的数量v_count:=SQL%ROWCOUNT ,然后再commit,后面再用if v_count=0 then ......来继续程序

  过程:

过程:(过程里的参数都是以P开头,begin....end里的参数都是以v开头----规范!)
     create or replace procedure procedure_name [(parameter_name[in|out|in out]type[,...])]{is |as }----parameter_name:可以向一个过程传递多个参数;
                    -----in|out|in out定义了参数的模式,
                      ---in:表示参数在程序运行的时候已经具有值,在过程体中不能改变IN参数的值;
                      ---out:参数只有在过程体内部赋值。
                      ---in out:参数当过程运行时可能已经具有值,但是在过程体中也可以修改此值。
begin
 procedure_body
end procedure_name;
   例:
create or replace procedure update_prdtest_sal(
p_prd_type in prdtest.prd_type%type,  ----定义参数
p_factor in number -----定义参数
) as
v_prdtest_count integer;
begin
    select count(*) into v_prdtest_count from prdtest where prd_type=p_prd_type;
    if v_prdtest_count=1 then
    update prdtest set sal=sal*p_factor where prd_type=p_prd_type;
    commit;
    end if ;
    exception
        when others then
        rollback;
        end update_prdtest_sal;
        /

   2)调用过程:
    call procedure_name(根据参数的模式决定参数):
    如上:call  update_prdtest_sal(1,1.5);
  3)获取有关过程的信息
    user_procedures
  4)删除过程
    drop procedure procedure_name
   如上: drop procedure update_prdtest_sal;
  5)查看过程中的错误:
    show errros;

函数
  函数与过程一样,唯一的区别就是函数必须向调用它的语句返回一个值。
  1)函数体不像过程体,它必须有返回值,其类型在return子句中指定。
  如下面:

   create or replace function circle_area(
  p_radius in number
) return number as
v_pi number:=3.14;
v_area number;
begin
v_area:=v_pi*power(p_radius,2);
return v_area;
end circle_area;
/

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有