Oracle基础 游标

系统 1724 0
原文: Oracle基础 游标

一、游标

游标用来处理从数据库中检索的多行记录(使用SELECT语句)。利用游标,程序可以逐个地处理和遍历一次检索返回的整个记录集。

     为了处理SQL语句,Oracle将在内存中分配一个区域,这就是上下文区。这个区包含了已经处理完的行数、指向被分析语句的指针,整个区是查询语句返回的数据行集。游标就是指向上下文区句柄或指针。

 

二、游标的分类:

  1、静态游标:静态游标是在编译时知道其SELECT语句的游标。静态游标又分为两种类型,隐式游标和显示游标。

  2、动态游标:用户为游标使用的查询直到运行的时候才能确定,可以使用REF游标和游标变量满足这个要求。为了使用引用游标,必须声明游标变量。有两种类型的REF游标:强类型REF游标和弱类型REF游标。

 

 

三、显示游标的用法:

  显示游标被用于处理返回多行数据的SELECT 语句,游标名通过CURSOR….IS 语句显示地赋给SELECT 语句。

        (一)使用步骤;

       1)声明游标: CURSOR cursor_name IS select_statement

        2)为查询打开游标: OPEN cursor_name

        3)取得结果放入PL/SQL变量中;

                  FETCH cursor_name INTO list_of_variables;

               FETCH cursor_name INTO PL/SQL_record;

        4)关闭游标。 CLOSE cursor_name

注意:在声明游标时, select_statement不能包含INTO子句。当使用显示游标时,INTO子句是FETCH语句的一部分。

  例:显示雇员的名称和薪水

      
        --
      
      
        使用LOOP遍历游标
      
      
        DECLARE
      
      
        

  v_name emp.ename
      
      
        %
      
      
        TYPE;

  v_sal emp.sal
      
      
        %
      
      
        TYPE;

  
      
      
        CURSOR
      
       cus_emp 
      
        IS
      
      
        SELECT
      
       ename,sal 
      
        FROM
      
       emp;                         
      
        --
      
      
        声明游标
      
      
        BEGIN
      
      
        OPEN
      
       cus_emp;                                       
      
        --
      
      
        打开游标
      
      
           LOOP 

      
      
      
        FETCH
      
       cus_emp 
      
        INTO
      
       v_name,v_sal;                 
      
        --
      
      
        提取游标
      
      
        EXIT
      
      
        WHEN
      
       cus_emp
      
        %
      
      
        NOTFOUND;

      dbms_output.put_line(
      
      
        '
      
      
      
        '
      
      
        ||
      
      cus_emp
      
        %
      
      
        ROWCOUNT
      
      
        ||
      
      
        '
      
      
        个用户:  name:
      
      
        '
      
      
        ||
      
      v_name
      
        ||
      
      
        '
      
      
             sal:
      
      
        '
      
      
        ||
      
      
        v_sal);

   
      
      
        END
      
      
         LOOP;

   
      
      
        CLOSE
      
       cus_emp;                                      
      
        --
      
      
        关闭游标
      
      
        END
      
      ;
    

  显示游标的属性:

%FOUND:只有在DML语句影响一行或者多行是,则返回TRUE;

  %NOTFOUND:没有影响任何行,则返回TRUE。

  %ROWCOUNT:返回DML语句影响的行数,没有影响则返回0;

  %ISOPEN:返回游标是否打开,在执行SQL之后,Oracle自动关闭SQL游标,所以隐式游标的%isopen属性始终未false;

 

  另一种方式:

      
        --
      
      
        使用for来简化游标遍历
      
      
        DECLARE
      
      
        CURSOR
      
       cus_emp 
      
        IS
      
      
        SELECT
      
       ename,sal 
      
        FROM
      
      
         emp;


      
      
        BEGIN
      
      
        FOR
      
       record_emp 
      
        IN
      
      
         cus_emp

   LOOP 

      dbms_output.put_line(
      
      
        '
      
      
      
        '
      
      
        ||
      
      cus_emp
      
        %
      
      
        ROWCOUNT
      
      
        ||
      
      
        '
      
      
        个用户:  name:
      
      
        '
      
      
        ||
      
      record_emp.ename
      
        ||
      
      
        '
      
      
             sal:
      
      
        '
      
      
        ||
      
      
        record_emp.sal);

   
      
      
        END
      
      
         LOOP;


      
      
        END
      
      ;
    

  record_emp是plsql声明的的记录变量,此变量的属性为声明为%ROWTYPE类型,作用域在FOR循环之内,即在FOR循环外就不能访问了。


  循环游标的特性:
  (1)从游标中提取了所有记录之后自动终止。
  (2)提取和处理游标中的每一条记录。
  (3)如果在提取记录之后%NOTFOUND属性返回TRUE,则终止循环。如果未返回任何行,则不进入循环。

 

游标案例:  

      
        --
      
      
        给员工加薪,按员工入职时间进行加薪,每年加100,1000封顶
      
      
        DECLARE
      
      
        

  v_date emp.hiredate
      
      
        %
      
      
        TYPE;

  v_empno emp.empno
      
      
        %
      
      
        TYPE;

  v_money 
      
      
        NUMBER
      
      
        ;

  
      
      
        CURSOR
      
       cur_emp 
      
        IS
      
      
        SELECT
      
       empno,hiredate 
      
        FROM
      
      
         emp;


      
      
        BEGIN
      
      
        OPEN
      
      
          cur_emp;

  LOOP

     
      
      
        FETCH
      
       cur_emp 
      
        INTO
      
      
         v_empno,v_date;

     
      
      
        EXIT
      
      
        WHEN
      
       cur_emp
      
        %
      
      
        NOTFOUND;

     v_money :
      
      
        =
      
      
        100
      
      
        *
      
      (
      
        1990
      
      
        -
      
      to_char(v_date,
      
        '
      
      
        yyyy
      
      
        '
      
      
        ));

     
      
      
        IF
      
       v_money
      
        <
      
      
        1000
      
      
        THEN
      
      
        UPDATE
      
       emp 
      
        SET
      
       sal
      
        =
      
      sal
      
        +
      
      v_money 
      
        WHERE
      
       empno
      
        =
      
      
        v_empno;

     
      
      
        ELSE
      
      
        UPDATE
      
       emp 
      
        SET
      
       sal
      
        =
      
      sal
      
        +
      
      
        1000
      
      
        WHERE
      
       empno
      
        =
      
      
        v_empno;

     
      
      
        END
      
      
        IF
      
      
        ;   

  
      
      
        END
      
      
         LOOP;


      
      
        END
      
      ;
    

 

四、隐式游标:

  所有的隐式游标都被假设为只返回一条记录。
  使用隐式游标时,用户无需进行声明、打开及关闭。PL/SQL隐含地打开、处理,然后关掉游标。多条sql语句 隐式游标SQL永远指的是最后一条sql语句的结果,主要使用在update 和 delete语句上。

  隐式游标的四个属性:

 

属性 说明
 SQL%rowcount  影响的记录的行数整数(用来判断插入,更新修改是否成功,必须在comit之前,否则提交后结果为0.)
 SQL%found  影响到了记录 true()
 SQL%notfound  没有影响到记录 true
 SQL%isopen  是否打开 布尔值 永远是false


例如:

      
        DECLARE
      
      
        

  row_emp emp
      
      
        %
      
      
        ROWTYPE;


      
      
        BEGIN
      
      
        SELECT
      
       ename,sal 
      
        INTO
      
      
         row_emp.ename,row_emp.sal

  
      
      
        FROM
      
       emp 
      
        WHERE
      
       emp.empno 
      
        =
      
      
        7369
      
      
        ;

  
      
      
        --
      
      
        判断是否查到数据
      
      
        if
      
      (SQL
      
        %
      
      
        ROWCOUNT
      
      
        =
      
      
        1
      
      ) 
      
        THEN
      
      
        

    dbms_output.put_line(
      
      
        '
      
      
        找到了
      
      
        '
      
      
        );

  
      
      
        END
      
      
        IF
      
      
        ;

  
      
      
        --
      
      
        另一种方式判断
      
      
        IF
      
      (SQL
      
        %
      
      Found) 
      
        THEN
      
      
        

    dbms_output.put_line(
      
      
        '
      
      
        找到了
      
      
        '
      
      
        );

  
      
      
        END
      
      
        IF
      
      
        ;



  dbms_output.put_line(
      
      
        '
      
      
        ename:
      
      
        '
      
      
        ||
      
      row_emp.ename
      
        ||
      
      
        '
      
      
            sal:
      
      
        '
      
      
        ||
      
      
        row_emp.sal);


      
      
        END
      
      ;
    

 

上述游标自动打开,并把相关值赋给对应变量,然后关闭。执行完后,PL/SQL变量rowemp.ename,rowemp.sal中已经有了值。


五:动态游标

  静态游标是在声明就已经确定查询语句,如果用户需要在运行时动态决定游标执行的查询,就需要使用动态游标(REF游标)。

  动态游标分为两类: 强类型游标 弱类型游标

  动态游标使用步骤:

  1、声明动态游标类型;

  2、打开游标,指定游标查询;

  3、提取游标。

  4、关闭游标。

  例:

强类型游标, 使用return声明的游标为强类型游标。在对游标进行绑定查询只能绑定游标返回的类型rowtype。

      
        --
      
      
        强类型的动态游标,查询emp表中的数据
      
      
        DECLARE
      
      
        

  TYPE ref_cur 
      
      
        IS
      
       REF 
      
        CURSOR
      
      
        --
      
      
        声明游标类型
      
      
        RETURN
      
       emp
      
        %
      
      ROWTYPE;       
      
        --
      
      
        带返回值的为强类型动态游标
      
      

  refcur_emp ref_cur;         
      
        --
      
      
        游标类型对象
      
      

  v_emp emp
      
        %
      
      
        ROWTYPE;


      
      
        BEGIN
      
      
        OPEN
      
       refcur_emp 
      
        FOR
      
      
        --
      
      
        将游标绑定到一个查询语句,因为声明的是强类型,所以只能绑定emp;
      
      
        SELECT
      
      
        *
      
      
        FROM
      
      
         emp;    

  LOOP

    
      
      
        FETCH
      
       refcur_emp 
      
        INTO
      
       v_emp;     
      
        --
      
      
        提取游标内容
      
      
        EXIT
      
      
        WHEN
      
       refcur_emp
      
        %
      
      
        NOTFOUND;

    dbms_output.put_line(refcur_emp
      
      
        %
      
      
        Rowcount
      
      
        ||
      
      
        '
      
      
        、name:
      
      
        '
      
      
        ||
      
      v_emp.ename
      
        ||
      
      
        '
      
      
            sal:
      
      
        '
      
      
        ||
      
      
        v_emp.sal);

  
      
      
        END
      
      
         LOOP;

  
      
      
        CLOSE
      
      
         refcur_emp;


      
      
        END
      
      ;
    

弱类型游标:可以用来绑定多个查询结果。

  例:

      
        --
      
      
        弱类型游标
      
      
        DECLARE
      
      
        

  TYPE refcur 
      
      
        IS
      
       REF 
      
        CURSOR
      
      ;   
      
        --
      
      
        未定义返回类型为弱类型游标
      
      
          rc refcur;

  v_name emp.ename
      
      
        %
      
      
        TYPE;

  v_deptname dept.dname
      
      
        %
      
      
        TYPE;


      
      
        BEGIN
      
      
        OPEN
      
       rc 
      
        FOR
      
      
        SELECT
      
       ename,dname 
      
        FROM
      
       emp e,dept d 
      
        WHERE
      
       e.deptno 
      
        =
      
       d.deptno;  
      
        --
      
      
        绑定查询
      
      
          LOOP

    
      
      
        FETCH
      
       rc 
      
        INTO
      
      
         v_name,v_deptname;    

    
      
      
        EXIT
      
      
        WHEN
      
       rc
      
        %
      
      
        NOTFOUND;

    dbms_output.put_line(
      
      
        '
      
      
        name:
      
      
        '
      
      
        ||
      
      v_name
      
        ||
      
      
        '
      
      
                       deptname:
      
      
        '
      
      
        ||
      
      
        v_deptname);

  
      
      
        END
      
      
         LOOP;

  
      
      
        CLOSE
      
      
         rc;


      
      
        END
      
      ;
    

 

  例:

      
        --
      
      
        根据输入的内容绑定游标
      
      
        DECLARE
      
      
         

  TYPE refcur 
      
      
        IS
      
       REF 
      
        CURSOR
      
      
        ;

  rc refcur;

  v_tablename 
      
      
        VARCHAR2
      
      (
      
        10
      
      ) :
      
        =
      
      
        '
      
      
        &tab
      
      
        '
      
      
        ;

  v_id 
      
      
        NUMBER
      
      
        ;

  v_name 
      
      
        VARCHAR2
      
      (
      
        20
      
      
        );


      
      
        BEGIN
      
      
        IF
      
      (v_tablename 
      
        =
      
      
        '
      
      
        e
      
      
        '
      
      ) 
      
        THEN
      
      
        OPEN
      
       rc 
      
        FOR
      
      
        SELECT
      
       e.empno,e.ename 
      
        INTO
      
       v_id,v_name 
      
        FROM
      
      
         emp e;

      dbms_output.put_line(
      
      
        '
      
      
        =========员工信息=============
      
      
        '
      
      
        );

  Elsif(v_tablename 
      
      
        =
      
      
        '
      
      
        d
      
      
        '
      
      ) 
      
        THEN
      
      
        OPEN
      
       rc 
      
        FOR
      
      
        SELECT
      
       d.deptno,d.dname 
      
        INTO
      
       v_id,v_name 
      
        FROM
      
      
         dept d;

      dbms_output.put_line(
      
      
        '
      
      
        =========部门信息=============
      
      
        '
      
      
        );

  
      
      
        ELSE
      
      
        

      dbms_output.put_line(
      
      
        '
      
      
        输入错误,请输入e或者d!
      
      
        '
      
      
        );

      
      
      
        RETURN
      
      
        ;

  
      
      
        END
      
      
        IF
      
      
        ;  

  

  LOOP 

    
      
      
        FETCH
      
       rc 
      
        INTO
      
      
         v_id,v_name;

    dbms_output.put_line(
      
      
        '
      
      
        #
      
      
        '
      
      
        ||
      
      rc
      
        %
      
      
        Rowcount
      
      
        ||
      
      
        '
      
      
           id:
      
      
        '
      
      
        ||
      
      v_id
      
        ||
      
      
        '
      
      
           name:
      
      
        '
      
      
        ||
      
      
        v_name);

    
      
      
        EXIT
      
      
        WHEN
      
       rc
      
        %
      
      
        NOTFOUND;

  
      
      
        END
      
      
         LOOP;


      
      
        END
      
      ;
    

 

Oracle基础 游标


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论