PL/SQL 之三 游标基础用法

来源:互联网 发布:零基础php好学吗 编辑:程序博客网 时间:2024/05/19 00:52
下面的内容主要来自《Oracle PL/SQL 实例精解》

1.定义

    游标:映射在结果集某一行数据的位置实体。

2.分类

     1.1静态游标
            1)显式游标
            2)隐式游标
     1.2 REF游标

3.隐式游标

     处理过程:
       1)该SQL语句不存在显示游标时,任何特定PL/SQL语句块都会产生一个隐式游标。
       2)它会自动的与DML语句建立关联。
       3)处理隐式游标时,Oracle会自动地执行OPEN\FETCH\CLOSE操作。
       4)最次一次被打开的游标称为SQL游标。     

4.显式游标

     对于返回多行数据的任何查询,都可以定义为显式游标,它常常在PL/SQL语句块的Declare部分对该游标进行声明。Declare部分定义的游标也就是静态游标。

     使用步骤:声明游标、打开游标、检索(取出)、关闭游标。示例如下:

DECLARE  CURSOR c_emp IS SELECT a.empno,a.ename FROM emp a; --1.声明游标      r_emp c_emp%ROWTYPE;--定义基于游标的记录变量BEGIN       IF c_emp%ISOPEN=FALSE THEN              OPEN c_emp;--2.打开游标       END IF;       LOOP             FETCH c_emp INTO r_emp; --3.检索数据             IF c_emp%NOTFOUND THEN                   EXIT;             ELSE                   dbms_output.put_line(r_emp.empno||' '||r_emp.ename);             END IF;       END LOOP;             IF c_emp%ISOPEN THEN              CLOSE c_emp; --关闭游标       END IF;END;     

5.游标的四大属性

     SQL%ISOPEN:它是布尔值,如果游标打开,则为true;游标关闭,则为false。对于隐式游标 SQL%Isopen一直是close,隐式游标在DML语句执行时打开,结束时关闭。
     SQL%Found:未执行任何DML语句之前,值为null;DML语句执行后,SQL%Found值变化如下:true:Insert\Delete\Update\Select into至少返回一行。
     SQL%NotFound:Fetch数据没有返回数据行时,返回True,否则返回False。 
     SQL%RowCount:没有执行任何DML语句之前,值为null;对于 SELECT INTO语句 执行成功返回1;Insert into 时返回1;没有成功返回0,同时产生一个no_data_found异常。

6.游标For循环和嵌套循环

    游标For循环,游标打开、检索、关闭的过程被隐含地实现了。
DECLARE  CURSOR c_zip IS SELECT * FROM zipcode; --定义游标  vr_zip c_zip%ROWTYPE;--定义基于游标的记录变量BEGIN      FOR vr_zip IN c_zip LOOP  --游标For循环,游标的打开、检索、关闭的过程被隐含的实现            dbms_output.put_line(vr_zip.zip||' '||vr_zip.city||'  '||vr_zip.state);      END LOOP;END;
嵌套游标示例:

--嵌套游标DECLARE  v_Section_id SECTION.SECTION_ID%TYPE;  v_num NUMBER(10);  CURSOR c_section_course IS  --父游标 收集某课程每个班级的信息      SELECT b.description,a.section_id FROM SECTION a,course b WHERE a.course_no=b.course_no;  CURSOR c_num IS   --子游标 统计每个section_id的注册数量      SELECT c.section_id,COUNT(c.student_id) num FROM SECTION a,course b,enrollment c      WHERE a.course_no=b.course_no AND a.section_id=c.section_id  AND c.section_id=v_Section_id      GROUP BY c.section_id;BEGIN      FOR r_section_course IN c_section_course LOOP            v_section_id:=r_section_course.section_id;            v_num:=0;            FOR r_num IN c_num LOOP                  v_num:=v_num+NVL(r_num.num,0);            END LOOP;        dbms_output.put_line(r_section_course.section_id||' ,'||r_section_course.description||' 数量'||v_num);      END LOOP;END;

7.注意事项

   7.1 游标Select列表,此列表与PL/SQL变量或者PL/SQL记录组件进行匹配。
   7.2 相同数据类型的游标,Oracle支持赋值,即多个游标变量指向同一共享区域,共享指向位置实体。
DECLARE   l_cv1    SYS_REFCURSOR;   l_cv2    SYS_REFCURSOR;   l_cv3    SYS_REFCURSOR;   l_name   user_objects.object_name%TYPE;BEGIN   OPEN l_cv1 FOR SELECT ename FROM emp ORDER BY empno;   FETCH l_cv1 INTO l_name;      --游标指向 SMITH 取出该值   DBMS_OUTPUT.put_line (l_name);   l_cv2 := l_cv1;     --L_cv2 是 L_cv1别名   FETCH l_cv2 INTO l_name;     --游标继续指向下一个数值 ALLEN   DBMS_OUTPUT.put_line (l_name);   l_cv3:=l_cv2;        --L_cv3 是l_cv1别名   FETCH l_cv3 INTO l_name;   dbms_output.put_line(l_name);   CLOSE l_cv1;--游标cv1关闭了, cv2|cv3也关闭了   FETCH l_cv2 INTO l_name;   DBMS_OUTPUT.put_line (l_name);       FETCH l_cv3 INTO l_name;       dbms_output.put_line(l_name);   CLOSE l_cv2;EXCEPTION   WHEN OTHERS   THEN      DBMS_OUTPUT.put_line ('......ERROR.....');END;

8.高级游标

   8.1 游标和嵌套游标中使用参数
       注意:游标参数可以有默认值;参数传递模型只能为IN
       示例:   
DECLARE  CURSOR c_zip(p_state IN zipcode.state%TYPE DEFAULT 'CT') --带游标参数          IS SELECT zip,city,state FROM zipcode WHERE state=p_state;BEGIN      FOR r_zip IN c_zip('NJ') LOOP      dbms_output.put_line(r_zip.zip||' '||r_zip.city||' '||r_zip.state);      END LOOP;                   FOR r_zip IN c_zip() LOOP --此时为'CT'      dbms_output.put_line(r_zip.zip||' '||r_zip.city||' '||r_zip.state);      END LOOP;END;

    8.2 FOR UPDATE和Where CURRENT游标
      使用游标更新数据库表时,需要使用FOR UPDATE子句。目的:锁定要更新的表,防止其他人在执行完更新操作和释放该锁之前进行更新操作。
      语法: 游标声明  for update ;  游标声明  for update of <item_name>;
             前者可以锁定到表多个数据项;后者可以锁定到表中成员某数据项。
      示例:   
declare  cursor c_course is select course_no,cost from course for update; begin      for r_course in c_course loop            if r_course.cost<2500 then                  update course                   set cost=r_course.cost+10                   where course_no=r_course.COURSE_NO;        end if;            end loop; commit;end;

当希望更新最新检索的数据行时,可以使用for current of,只能在for update of 游标中使用 where current of 子句,好处是免于在update子句中使用where子句。

0 0
原创粉丝点击