设为首页 收藏本站
查看: 566|回复: 0

[经验分享] Oracle学习笔记整理之游标篇

[复制链接]

尚未签到

发表于 2016-7-30 13:18:46 | 显示全部楼层 |阅读模式
  转自:http://www.itpub.net/thread-1394528-1-1.html
  游标分为隐式、显式、REF三种游标。
而隐式游标和显式游标又都属于静态游标,REF游标属于动态游标。
静态游标和动态游标的最大区别在于静态游标是在运行前将游标变量和SQL关联,而动态游标恰恰相反是在运行后将游标变量和SQL进行关联。
隐式游标是由Oracle自动管理,也称sql游标。所有的DML都被Oracle解析成为一个名为SQL的隐式游标。DML包括Insert、Delete、Update、Merge into。而Select属于DQL。
隐式游标的属性有:

    属性名                说明
  sql%found影响行数大于等于1是为 ture
  sql%notfound没有影响行是为true
  sql%rowcount受影响的行数
  sql%isopen游标是否打开,始终为false
  sql%bulk_rowcount(index)...
  sql%bulk_exceptions(index).error_index...
  sql%bulk_exceptions(index).error_code

  
隐式游标实例:
begin
  --执行DML操作
  update chg_test_b b set b.chg_name = 'ff' where b.chg_id = 5;
  --判断是否有受影响行
  if sql%found then
    --打印受影响行数
    dbms_output.put_line('影响行数:' || sql%rowcount);
  end if;
  --判断是否没有受影响行
  if sql%notfound then
    dbms_output.put_line('id为5的记录不存在');
  end if; 
end;
无参显式游标实例:
declare
  --声明游标表变量并关联sql
  cursor rowList is
    select * from chg_test_b b;
  --声明行变量
  --如果上面的查询语句只有一个查询字段,这里也可以使用正常的变量声明方式(v_rowValue varchar2(20);)。
  rowValue chg_test_b%rowtype;
begin
  open rowList; --打开游标
  --如果确定由表中只有一条记录的话,loop和end loop可以不写,而exit必须存在于游标循环内,所以也不需要写。
  loop
    fetch rowList
      into rowValue; --取出游标内的值放到rowValue中
    exit when rowList%notfound; --判断是否还存在记录,如果不存在终止游标
    dbms_output.put_line(rowValue.chg_name); --将的到的值打印,如果查询只有一个字段这里只需写变量名即可。
  end loop;
  close rowList; --关闭游标
end;
有参显式游标实例:
declare
  --声明带参数的游标变量并关联sql,并将参数与sql进行关联
  cursor rowList(c_name varchar2, c_id number) is
    select * from chg_test_b b where b.chg_name = c_name and b.chg_id = c_id;
  --声明行变量
  --如果上面的查询语句只有一个查询字段,这里也可以使用正常的变量声明方式(v_rowValue varchar2(20);)。
  rowValue chg_test_b%rowtype;
begin
  open rowList('chg1', 1); --打开游标,并将参数给出
  --如果确定由表中只有一条记录的话,loop和end loop可以不写,而exit必须存在于游标循环内,所以也不需要写。
  loop
    fetch rowList
      into rowValue; --取出游标内的值放到rowValue中
    exit when rowList%notfound;--判断是否还存在记录,如果不存在终止游标
    dbms_output.put_line(rowValue.chg_name); --将的到的值打印,如果查询只有一个字段这里只需写变量名即可。
  end loop;
  close rowList; --关闭游标
end;
在游标内进行DML操作实例:
declare
  --声明游标变量,并关联sql
  --如果要在游标内执行DML操作,必须使用for update。
  --使用for update后你所操作的行或列将会被锁,如果这时其他人操作就会进入等待状态。
  --如果你在执行select时记录被锁,那么就会进入等待状态,
  --为了避免这种情况可以在 for update后使用 nowait,这样你的结果就可以立即返回,但不建议使用
  --如果被锁在打开游标时会报出ORA-00054资源正忙异常,需捕获异常进行处理
  --使用of的区别时锁字段和锁行。
  cursor rowList is
    select b.* from chg_test_b b for update of b.chg_name nowait;
  --如果上面的查询语句只有一个查询字段,这里也可以使用正常的变量声明方式(v_rowValue varchar2(20);)。
  rowValue chg_test_b%rowtype;
  v_i      number(11);
begin
  v_i := 1;
  open rowList; --打开游标
  --如果确定由表中只有一条记录的话,loop和end loop可以不写,而exit必须存在于游标循环内,所以也不需要写。
  loop
    fetch rowList
      into rowValue; --取出游标内的值放到rowValue中
    exit when rowList%notfound;--判断是否还存在记录,如果不存在终止游标
    dbms_output.put_line(rowValue.chg_name); --将的到的值打印,如果查询只有一个字段这里只需写变量名即可。
    --执行DML操作
    update chg_test_b b
       set b.chg_name = 'chg' || v_i
     where current of rowList;
    v_i := v_i + 1;
  end loop;
  close rowList; --关闭游标
  commit;
end;
循环游标实例:
循环游标不需要手动进行打开和管理操作,全部由oracle进行管理。for yy in xx 等同于fetch xx into yy;
declare
  --声明游标变量并关联sql
  cursor rowList is
    select level a from dual connect by level <= 10;
begin
  for rowValue in rowList loop
    --rowValue是每条记录不需要事先声明,rowList是集合中的所有记录
    dbms_output.put_line(rowValue.a);--取出集合中的值进行打印
  end loop;
end;


declare
begin
  --可以将select语句for xx in 内,无论传参或是嵌套更为方便简洁。
  for rowValue in (select level a from dual connect by level <=10) loop
     for rv in (select col1 from tab1 where tab1.id = rowValue.a) loop
         dbms_output.put_line(rv.col1 );--将的到的值打印。
     end loop;
  end loop;
end;


declare
begin
  for rowValue in 1..10 loop
    dbms_output.put_line(rowValue);--将的到的值打印,如果查询只有一个字段这里只需写变量名即可。
  end loop;
end;
REF游标实例:
declare
  type cus_cur_type is ref cursor return chg_test_b%rowtype; --强类型Ref游标,查询的sql必须返回chg_test_b表类型
   --type cus_cur_type is ref cursor;弱类型Ref游标,返回类型没有限制
  rowList cus_cur_type; -- 声明游标变量
  rowValue chg_test_b%rowtype; --声明行变量
begin
  open rowList for --打开游标,并关联sql
    select * from chg_test_b b;
  loop
    fetch rowList
      into rowValue; --按行取出数据
    exit when rowList%notfound;--判断是否还存在记录,如果不存在终止游标
    dbms_output.put_line(rowValue.chg_name);--将的到的值打印,如果查询只有一个字段这里只需写变量名即可。
  end loop;
  close rowList;--关闭游标
end;
  
  
  ---------------------------------------------------------------
  CREATE TABLE T (N1 NUMBER,C1 VARCHAR2(1));
  

  INSERT INTO T VALUES (1,NULL);
  INSERT INTO T VALUES (2,NULL);
  INSERT INTO T VALUES (2,NULL);
  INSERT INTO T VALUES (3,NULL);
  INSERT INTO T VALUES (3,NULL);
  INSERT INTO T VALUES (3,NULL);
  INSERT INTO T VALUES (4,NULL);
  INSERT INTO T VALUES (4,NULL);
  

  ----sql%bulk_rowcount(index)使用例子
  DECLARE
     TYPE num_t IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
     lv_num num_t;
  BEGIN
     lv_num(1):=2;
     lv_num(2):=3;
     lv_num(3):=4;
     lv_num(4):=1;
     
     FORALL i IN 1..lv_num.COUNT  ---- 批量执行UPDATE, 里面其实有三个UPDATE
        UPDATE t SET c1=n1 WHERE n1=lv_num(i);
     
     FOR i IN 1..lv_num.COUNT LOOP
         --- SQL%ROWCOUNT(i)告诉你每个UPDATE执行了多少行
         DBMS_OUTPUT.PUT_LINE('n1='||lv_num(i)||' '||SQL%BULK_ROWCOUNT(i)||' rows updated');
     END LOOP;
  END;
  /
  

  输出:
  n1=2 2 rows updated
  n1=3 3 rows updated
  n1=4 2 rows updated
  n1=1 1 rows updated
  

  

  PL/SQL procedure successfully completed.
  

  

  SELECT * FROM T;
  

  

          N1 C
  ---------- -
           1 1
           2 2
           2 2
           3 3
           3 3
           3 3
           4 4
           4 4
  

  8 rows selected.
  

  ----sql%bulk_exceptions(index).error_index sql%bulk_exceptions(index).error_code 使用例子
  DECLARE
     TYPE num_t IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
     lv_num num_t;
  

     dml_errors EXCEPTION;
     lv_err_cnt number := 0;
     PRAGMA exception_init(dml_errors, -24381);
  

  BEGIN
     lv_num(1):=2;
     lv_num(2):=3;
     lv_num(3):=4;
     lv_num(4):=1;
                 
     BEGIN
        FORALL i IN 1 .. lv_num.count SAVE EXCEPTIONS
           UPDATE t SET c1=n1*4 WHERE n1=lv_num(i);     --- n1*4 在n1=3和4的时候将会溢出,因为c1定义是VARCHAR2(1)
     EXCEPTION
         WHEN dml_errors THEN
              lv_err_cnt := SQL%BULK_EXCEPTIONS.COUNT;
              
              DBMS_OUTPUT.PUT_LINE('There are '||lv_err_cnt||' errors');
              
              FOR i IN 1..lv_err_cnt LOOP
                  DBMS_OUTPUT.PUT_LINE('error number '||i
                                       ||' happened in index '||SQL%BULK_EXCEPTIONS(i).ERROR_INDEX  ---- lv_num数组的下标
                                       ||' data='||lv_num(SQL%BULK_EXCEPTIONS(i).ERROR_INDEX)
                                       ||' error code='||SQL%BULK_EXCEPTIONS(i).ERROR_CODE
                                       ||' error msg='||SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE) ---- 根据错误代码反推错误信息
                                       );
              END LOOP;
     END;
     
  END pr_copy_data;
  /
  

  输出:
  There are 2 errors
  error number 1 happened in index 2 data=3 error code=12899 error msg=ORA-12899: value too large for column  (actual: , maximum: )
  error number 2 happened in index 3 data=4 error code=12899 error msg=ORA-12899: value too large for column  (actual: , maximum: )
  

  PL/SQL procedure successfully completed.
  

  

  SELECT * FROM T;
  

          N1 C
  ---------- -
           1 4     ---- c1 被修改为 N1*4
           2 8     ---- c1 被修改为 N1*4
           2 8     ---- c1 被修改为 N1*4
           3 3     ---- 以下 c1 保持原样因为 N1*4 溢出了
           3 3
           3 3
           4 4
           4 4
  

  8 rows selected.
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-251307-1-1.html 上篇帖子: (转)Oracle维护常用SQL语句 下篇帖子: 详解ORACLE数据库的分区表
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表