Oracle】PL/SQL 显式游标、隐式游标、动态游标

本文深入探讨PL/SQL中的游标概念,包括显式游标、游标属性、游标FOR循环、更新或删除当前游标数据以及动态游标的使用方法。详细介绍了如何在PL/SQL中声明、打开、提取和关闭游标,以及如何利用游标进行数据处理。

在PL/SQL块中执行SELECT、INSERT、DELETE和UPDATE语句时,ORACLE会在内存中为其分配上下文区(Context Area),即缓冲区。游标是指向该区的一个指针,或是命名一个工作区(Work Area),或是一种结构化数据类型。

在每个用户会话中,可以同时打开多个游标,其数量由数据库初始化参数文件中的OPEN_CURSORS参数定义。

处理显式游标


    DECLARE  
       CURSOR c4(dept_id NUMBER, j_id VARCHAR2) --1、声明游标,有参数没有返回值  
       IS  
          SELECT first_name f_name, hire_date FROM employees  
          WHERE department_id = dept_id AND job_id = j_id;  
      
        --基于游标定义记录变量,比声明记录类型变量要方便,不容易出错  
        v_emp_record c4%ROWTYPE;  
    BEGIN  
       OPEN c4(90, 'AD_VP');             --2、打开游标,传递参数值  
       LOOP  
          FETCH c4 INTO v_emp_record;    --3、提取游标fetch into  
          IF c4%FOUND THEN  
             DBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是'  
                                ||v_emp_record.hire_date);  
          ELSE  
             DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');  
             EXIT;  
          END IF;  
       END LOOP;  
       CLOSE c4;                         --4、关闭游标  
    END;  

退出LOOP或者用:

EXIT WHEN c4%NOTFOUND;

游标属性:

Cursor_name%FOUND 布尔型属性,当最近一次提取游标操作FETCH成功则为 TRUE,否则为FALSE;

Cursor_name%NOTFOUND 布尔型属性,与%FOUND相反;——注意区别于DO_DATA_FOUND(select into抛出异常)

Cursor_name%ISOPEN 布尔型属性,当游标已打开时返回 TRUE;
Cursor_name%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。
游标的for循环

PL/SQL语言提供了游标FOR循环语句,自动执行游标的OPEN、FETCH、CLOSE语句和循环语句的功能;

当进入循环时,游标FOR循环语句自动打开游标,并提取第一行游标数据;
当程序处理完当前所提取的数据而进入下一次循环时,游标FOR循环语句自动提取下一行数据供程序处理;
当提取完结果集合中的所有数据行后结束循环,并自动关闭游标。

格式:
FOR index_variable IN cursor_name[(value[, value]…)] LOOP
– 游标数据处理代码
END LOOP;

其中:

index_variable为游标FOR 循环语句隐含声明的索引变量,该变量为记录变量,其结构与游标查询语句返回的结构集合的结构相同。在程序中可以通过引用该索引记录变量元素来读取所提取的游标数据,index_variable中各元素的名称与游标查询语句选择列表中所制定的列名相同。如果在游标查询语句的选择列表中存在计算列,则必须为这些计算列指定别名后才能通过游标FOR 循环语句中的索引变量来访问这些列数据。

DECLARE  
  CURSOR c_cursor(dept_no NUMBER DEFAULT 10)   
  IS  
    SELECT department_name, location_id FROM departments WHERE department_id <= dept_no;  
BEGIN  
    --当dept_no参数值为30  
    FOR c1_rec IN c_cursor(30) LOOP          
         DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);  
    END LOOP;  
     
    --使用默认的dept_no参数值10  
    FOR c1_rec IN c_cursor LOOP         
         DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);  
    END LOOP;  
END;  

更新或删除当前游标数据

游标查询语句中必须使用FOR UPDATE选项,以便在打开游标时锁定游标结果集合在表中对应数据行的所有列和部分列。

如果另一个会话已对活动集中的行加了锁,那么SELECT FOR UPDATE操作一直等待到其它的会话释放这些锁后才继续自己的操作;对于这种情况,当加上NOWAIT子句时,如果这些行真的被另一个会话锁定,则OPEN立即返回并给出:

ORA-0054 :resource busy and acquire with nowait specified.

DECLARE   
    V_deptno employees.department_id%TYPE :=&p_deptno;  
    CURSOR emp_cursor   
  IS   
  SELECT employees.employee_id, employees.salary   
    FROM employees WHERE employees.department_id=v_deptno  
  FOR UPDATE NOWAIT;                    --1、for update  
BEGIN  
    FOR emp_record IN emp_cursor LOOP  
      IF emp_record.salary < 1500 THEN  
        UPDATE employees SET salary=1500  
            WHERE CURRENT OF emp_cursor; --2、WHERE CURRENT OF cursor_name子句  
      END IF;  
    END LOOP;  
END;   

动态游标

与游标一样,动态游标(游标变量)也是一个指向多行查询结果集合中当前数据行的指针。但与游标不同的是,游标变量是动态的,而游标是静态的。

游标只能与指定的查询相连,即固定指向一个查询的内存处理区域,而游标变量则可与不同的查询语句相连,它可以指向不同查询语句的内存处理区域(但不能同时指向多个内存处理区域,在某一时刻只能与一个查询语句相连),只要这些查询语句的返回类型兼容即可。

DECLARE  
   --定义一个游标数据类型  
   TYPE emp_cursor_type IS REF CURSOR;  
   --声明一个游标变量  
   c1 EMP_CURSOR_TYPE;  
   --声明两个记录变量  
   v_emp_record employees%ROWTYPE;  
   v_reg_record regions%ROWTYPE;  
  
BEGIN  
   OPEN c1 FOR SELECT * FROM employees WHERE department_id = 20;  
   LOOP  
      FETCH c1 INTO v_emp_record;  
      EXIT WHEN c1%NOTFOUND;  
      DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name||'的雇佣日期是'  
                            ||v_emp_record.hire_date);  
   END LOOP;  
   --将同一个游标变量对应到另一个SELECT语句  
   OPEN c1 FOR SELECT * FROM regions WHERE region_id IN(1,2);  
   LOOP  
      FETCH c1 INTO v_reg_record;  
      EXIT WHEN c1%NOTFOUND;  
      DBMS_OUTPUT.PUT_LINE(v_reg_record.region_id||'表示'  
                            ||v_reg_record.region_name);  
   END LOOP;  
   CLOSE c1;  
END;
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值