zoukankan      html  css  js  c++  java
  • Oracle的cursor游标

    游标
    1. 什么是游标?
    游标是在关系数据库中用来操作记录结果集。
    游标指示结果集的当前位置,即游标跟踪结果集中的位置,并允许对结果集逐行执行多个操作,
    在这个过程中可能返回至原始表,也可能不返回至原始表。
    换句话说,游标从概念上讲基于数据库的表返回结果集。
    由于它指示结果集中的当前位置 ,就像计算机屏幕上的光标指示当前位置一样,
    “游标”由此得名。

    2.游标的基本原理:
    在oracle中,会为sql的CURD操作在内存中分配一个缓冲区,游标就是指向该区的一个指针。
    这里一般来说是指通过查询出来的结果集,结果集存放在缓冲区中,游标指向该结果集,
    可以指向结果集中的任何一行数据,
    开始时,它会指向首记录,
    它可以对结果集进行逐行操作,也就是说它为应用程序提供一种对结果集进行行操作的方法。

    3.游标的作用?
    3.1 指定结果集中特定行位置
    3.2 基于当前的结果集位置检索一行或连续多行
    3.3 在结果集的当前位置修改行中的数据
    3.4 对其他用户所做的数据更改定义不同的敏感性级别
    3.5 可以以编程的方式访问数据库

    4.为什么避免使用游标?
    4.1 在创建游标时,最需要考虑的事情是,“是否有办法避免使用游标?”
    因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;
    如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。

    5.游标的类型:
    5.1 分类为两种,静态和REF(动态)
    静态就像一个数据快照,打开游标后的结果集是对数据库的一个备份
    数据不随对表执行DML操作后而改变。
    静态分为显式与隐式游标
    隐式游标由oracle自动管理,用户控制不了,不检测数据行的变化
    显式游标在使用前必须先声明或者定义,这样的游标通常会关联数据查询语句,
    返回结果集
    REF(游动)游标:动态关联结果集的临时对象
    动态与静态的区别在于,sql语句通过编译,运行,才会显示出结果。
    在运行时,sql语句是不变的,那么这个游标才是静态的;
    sql语句是变化的,那么这个游标是动态的。

    6.显示游标
    声明--》打开--》loop --》 读取--》
    判断游标属性,走“读取” ,或者“关闭” --》end loop ---》 关闭

    7.游标属性
    %Found :Fetch语句(获取记录)执行情况 True or False。
    %NotFound : 最后一条记录是否提取出 True or False。
    %ISOpen : 游标是否打开True or False。
    %RowCount :游标当前提取的行数,并非结果集中的记录数。

    8.为游标传递参数

    9.隐式游标
    每当执行select活DML语句时,PL/SQL会自动打开一个隐式游标
    特性: 隐式游标由PL/SQL(ORACLE)自动管理;
    默认名称为SQL;
    select 或DML操作会产生隐式游标
    隐式有标的属性值始终是最新执行的SQL语句的结果值
    SQL游标和cursor for 游标是Oracle内置的游标
    SQL游标与当前会话有关,当前会话中的update,delete都会影响SQL隐式游标的属性
    cursor for游标用于循环

    10.隐式游标的属性
    sql%isopen 判断当前游标是否打开,打开为true,没有为false;
    sql%rowcount 对于DML语句,该属性值为受影响的数据行数。
    对于select语句,如果发生异常,其值为1
    sql%found 对于DML语句,该属性表明表中是否有数据值受影响。没有影响为false,
    有影响为true.
    对于select语句,如果发生异常,其值为true
    sql%notfound 与属性sql%found正好相反


    11. REF游标
    动态游标不与特定的查询绑定,在打开游标时,才确定对应的sql。
    REF游标可以对应多个查询。
    分为两类,强类型与弱类型游标

    强类型REF游标
    不指定游标的查询,需要定义游标的类型。
    --------------
    REF游标时ref类型的变量,还有return语句,
    type 游标类型 is ref cursor
    return 记录类型
    -----------------

    打开动态游标
    open 游标变量 for <select语句>


    弱类型REF游标
    与强类型REF游标的区别在于,没有return 类型
    type 游标类型 is ref cursor

    /**
    游标
      基于结果集的, 可以对结果集进行逐行操作。
    
    游标的类型: 
       静态就像一个数据快照,打开游标后的结果集是对数据库的一个备份
        数据不随对表执行DML操作后而改变。
        静态分为显式与隐式游标
          隐式游标由oracle自动管理,用户控制不了,不检测数据行的变化
          显式游标在使用前必须先声明或者定义,这样的游标通常会关联数据查询语句,
            返回结果集
        REF(游动)游标:动态关联结果集的临时对象
      
    游标的使用顺序
      1. 定义或者声明
      2. 打开
      3. 使用
      4. 关闭
      5. 释放(在sql server中存在,在oracle中不存在)
    获取游标的数据
       fetch  [next| prior | first | 
       last | absolute n | relative n from ]  游标名 into 变量 
       --批量提取数据
       fetch  游标名 bulk collect into 变量名 limit (限制条数)
    游标属性
      %Found :Fetch语句(获取记录)执行情况 True or False。
      %NotFound : 最后一条记录是否提取出 True or False。
      %ISOpen : 游标是否打开True or False。
      %RowCount :游标当前提取的行数,并非结果集中的记录数。  
       
    for...in...loop
    end loop;
    
     */     
     /***************************/
    -- 游标的定义 
    /***************************/
    declare 
    --声明游标cursor
     cursor myCur is select * from a;
     --声明列变量,类型为a.aname的类型
     var_n a.aname%type;
     --声明列变量,类型为a.age的类型
     var_age a.age%type;
     --声明行变量,类型是游标的行类型
     var_row myCur%rowtype;
     begin 
       --打开游标,此时游标的指向是结果集中首条记录
       open myCur;
       --使用loop循环读取多行数据,游标指针就会不断的前进
       --没有loop,读取当行记录
       loop
         --读取行数据, myCur只能给行类型,
         fetch myCur  into  var_age;
         --需要有退出的操作,否则一直往下走,直到卡死
         exit when  myCur%notFound;
         dbms_output.put_line(var_age); 
       
       end loop;
       --关闭游标,结束资源
       close myCur;
     end;
    /***************************/
    --使用游标的属性。 其中insert into 之后,不需要commit,它会自动提交
    /***************************/
    declare
    begin
      insert into a values (4, 'la4', '12'); 
      if SQL%found then
        DBMS_OUTPUT.put_line('insert values');
      else
        DBMS_OUTPUT.put_line('no insert values');
      end if;
    end;
    /***************************/
    --遍历循环游标loop, 
    /***************************/
    declare
      cursor mycur is select a.aid, a.aname,a.age from a;
      vara a.aid%type;
      varb a.aname%type;
      varc a.age%type;
    begin
      open mycur;
      fetch mycur into vara,varb,varc;
      dbms_output.put_line('vara:'||vara);
      dbms_output.put_line('varb:'||varb);
      dbms_output.put_line('varc:'||varc);
      close mycur;
    end;
    --
    declare
      cursor mycur is select a.aid, a.aname,a.age from a;
      varrow mycur%rowtype;  
    begin 
      open mycur;
      loop
           fetch mycur into varrow;
           exit  when mycur%notfound; 
           dbms_output.put_line('-------'||mycur%rowcount||'-------');
           dbms_output.put_line('1:'||varrow.aid||',2:'||varrow.aname||',3:'||varrow.age); 
      end loop;
      close mycur;
    end;
    --使用For循环遍历游标, 不需要声明变量,也不需要打开游标,不需要关闭游标
    declare
      cursor mycur is
        select a.aid, a.aname, a.age from a;
    begin   
      for varrow in mycur loop
        dbms_output.put_line('-------' || mycur%rowcount || '-------');
        dbms_output.put_line('1:' || varrow.aid || ',2:' || varrow.aname ||
                             ',3:' || varrow.age); 
      end loop;
    end;
    /************************** 
    --更新和删除显示游标中的记录
    --UPDATE或DELETE语句中的WHERE CURRENT OF子串
    专门处理要执行UPDATE或DELETE操作的表中取出的最近的数据。
      要使用这个方法,在声明游标时必须使用FOR UPDATE子串,
      当对话使用FOR UPDATE子串打开一个游标时,
      所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,
      其他对象只能查询这些数据行,
      不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。
       在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,
       那么所有表中选择的数据行都将被锁定。
       如果这些数据行已经被其他会话锁定,那么正常情况下ORACLE将等待,
       直到数据行解锁。 
    **************************/
    declare
      cursor mycur is
        select * from a for update;
      var_name a.aname%type;
      var_temp a.aname%type;
      var_row  mycur%rowtype;
    begin
      open mycur;
      loop
        fetch mycur
          into var_row;
        var_name := var_row.aname;
        dbms_output.put_line(var_name);
        exit when mycur%notfound;
        case (var_name)
          when 'a1' then
            var_temp := 'A';
          when 'a2' then
            var_temp := 'U';
          else
            var_temp := null;
        end case;
        --where current of mycur锁定当前行,
        --update之后需要commit提交事务,才能在数据库中保证变化,不能加在loop之内,
        --那样会影响mycur的指针指向
        update a set a.aname = a.aname || var_temp where current of mycur;
      end loop;
      commit;
      close mycur;
    end;
    
    
    
    -->http://www.cnblogs.com/shengtianlong/archive/2010/12/31/1922767.html
    /*
    select * from A;
    select * from B;*/
    View Code

    >Oracle中Cursor使用

  • 相关阅读:
    Hive的安装和使用
    Redis 慢查询日志
    GO语言-数组
    ZooKeeper-3.3.4集群安装配置
    GO语言-基础语法:循环
    GO语言-基础语法:条件判断
    GO语言-基础语法:变量定义
    nginx限制下载速度
    Centos7下Etcd集群搭建
    浅谈spj
  • 原文地址:https://www.cnblogs.com/alisonGavin/p/7381123.html
Copyright © 2011-2022 走看看