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

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

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

对于不一样的SQL语句,游标的使用状况不一样:数据库

SQL语句oracle

游标fetch

非查询语句ui

隐式的spa

结果是单行的查询语句.net

隐式的或显示的指针

结果是多行的查询语句blog

显示的

 

处理显式游标

例:

  1. DECLARE  
  2.    CURSOR c4(dept_id NUMBER, j_id VARCHAR2) --一、声明游标,有参数没有返回值  
  3.    IS  
  4.       SELECT first_name f_name, hire_date FROM employees  
  5.       WHERE department_id = dept_id AND job_id = j_id;  
  6.   
  7.     --基于游标定义记录变量,比声明记录类型变量要方便,不容易出错  
  8.     v_emp_record c4%ROWTYPE;  
  9. BEGIN  
  10.    OPEN c4(90, 'AD_VP');             --二、打开游标,传递参数值  
  11.    LOOP  
  12.       FETCH c4 INTO v_emp_record;    --三、提取游标fetch into  
  13.       IF c4%FOUND THEN  
  14.          DBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是'  
  15.                             ||v_emp_record.hire_date);  
  16.       ELSE  
  17.          DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');  
  18.          EXIT;  
  19.       END IF;  
  20.    END LOOP;  
  21.    CLOSE c4;                         --四、关闭游标  
  22. 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循环语句,自动执行游标的OPENFETCHCLOSE语句和循环语句的功能;

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

格式:

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

 

其中:

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

例:

  1. DECLARE  
  2.   CURSOR c_cursor(dept_no NUMBER DEFAULT 10)   
  3.   IS  
  4.     SELECT department_name, location_id FROM departments WHERE department_id <= dept_no;  
  5. BEGIN  
  6.     --当dept_no参数值为30  
  7.     FOR c1_rec IN c_cursor(30) LOOP          
  8.          DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);  
  9.     END LOOP;  
  10.      
  11.     --使用默认的dept_no参数值10  
  12.     FOR c1_rec IN c_cursor LOOP         
  13.          DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);  
  14.     END LOOP;  
  15. END;  


或者能够在游标FOR循环语句中使用子查询

  1. BEGIN  
  2.     FOR c1_rec IN(SELECT department_name, location_id FROM departments) LOOP   
  3.        DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);  
  4.     END LOOP;  
  5. END;  


处理隐式游标

显式游标主要是用于对查询语句的处理,尤为是在查询结果为多条记录的状况下;

而对于非查询语句,如修改、删除操做,则由ORACLE 系统自动地为这些操做设置游标并建立其工做区,隐式游标的名字为SQL,这是由ORACLE 系统定义的。

对于隐式游标的操做,如定义、打开、取值及关闭操做,都由ORACLE 系统自动地完成,无需用户进行处理。用户只能经过隐式游标的相关属性,来完成相应的操做。在隐式游标的工做区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据。

格式调用为: SQL%

  1. DECLARE  
  2.    v_rows NUMBER;  
  3. BEGIN  
  4.    --更新数据  
  5.    UPDATE employees SET salary = 30000  
  6.      WHERE department_id = 90 AND job_id = 'AD_VP';  
  7.    --获取默认游标的属性值  
  8.    v_rows := SQL%ROWCOUNT;  
  9.    DBMS_OUTPUT.PUT_LINE('更新了'||v_rows||'个雇员的工资');  
  10.      
  11.     --删除指定雇员;若是部门中没有雇员,则删除部门  
  12.     DELETE FROM employees WHERE department_id=v_deptno;  
  13.     IF SQL%NOTFOUND THEN  
  14.         DELETE FROM departments WHERE department_id=v_deptno;  
  15.     END IF;  
  16. END;  


更新或删除当前游标数据

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

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

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



  1. DECLARE   
  2.     V_deptno employees.department_id%TYPE :=&p_deptno;  
  3.     CURSOR emp_cursor   
  4.   IS   
  5.   SELECT employees.employee_id, employees.salary   
  6.     FROM employees WHERE employees.department_id=v_deptno  
  7.   FOR UPDATE NOWAIT;                    --一、for update  
  8. BEGIN  
  9.     FOR emp_record IN emp_cursor LOOP  
  10.       IF emp_record.salary < 1500 THEN  
  11.         UPDATE employees SET salary=1500  
  12.             WHERE CURRENT OF emp_cursor; --二、WHERE CURRENT OF cursor_name子句  
  13.       END IF;  
  14.     END LOOP;  
  15. END;   


动态游标

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

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


    1. DECLARE  
    2.    --定义一个游标数据类型  
    3.    TYPE emp_cursor_type IS REF CURSOR;  
    4.    --声明一个游标变量  
    5.    c1 EMP_CURSOR_TYPE;  
    6.    --声明两个记录变量  
    7.    v_emp_record employees%ROWTYPE;  
    8.    v_reg_record regions%ROWTYPE;  
    9.   
    10. BEGIN  
    11.    OPEN c1 FOR SELECT * FROM employees WHERE department_id = 20;  
    12.    LOOP  
    13.       FETCH c1 INTO v_emp_record;  
    14.       EXIT WHEN c1%NOTFOUND;  
    15.       DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name||'的雇佣日期是'  
    16.                             ||v_emp_record.hire_date);  
    17.    END LOOP;  
    18.    --将同一个游标变量对应到另外一个SELECT语句  
    19.    OPEN c1 FOR SELECT * FROM regions WHERE region_id IN(1,2);  
    20.    LOOP  
    21.       FETCH c1 INTO v_reg_record;  
    22.       EXIT WHEN c1%NOTFOUND;  
    23.       DBMS_OUTPUT.PUT_LINE(v_reg_record.region_id||'表示'  
    24.                             ||v_reg_record.region_name);  
    25.    END LOOP;  
    26.    CLOSE c1;  
    27. END; 
相关文章
相关标签/搜索