游标

2018-09-01  本文已影响0人  _拾年丶
游标:用来提取多行数据

Oracle 打开一个工作区(内存区域)来保存多行查询的结果集,
游标就是给这个工作区命的名称,并能用于处理由多行查询而返回的记录行。

隐式游标: 默认的 DML 语句和 select 语句都有隐式游标。
显示游标: 开发中给工作区命名,并且可以进行操作。

%ISOPEN Boolean 游标打开,则返回True(游标打开之后,不能再次打开,游标关闭之后,不能再次关闭)
%NOTFOUND Boolean 如果最近抓取没有获得记录,返回True
%FOUND Boolean 如果最近抓取获得记录,返回True
%ROWCOUNT Number 返回到目前为止获取的记录数


使用游标的步骤:

  1. 定义游标 CURSOR c_tb_stuu IS SELECT * FROM tb_stuu;
  2. 打开游标 OPEN c_tb_stuu;
  3. fetch游标 FETCH c_tb_stuu INTO r_tb_stuu;
    游标有个指针,默认指向第一行之上,fetch将指针向下移动,指向第N行数据,
    如果有数据,NOTFOUND返回false,FOUND返回true。
    如果到末尾,会一直抓取最后一条数据
  4. 关闭游标 CLOSE c_tb_stuu;

第一个例子: 使用游标提取 tb_stuu 的所有数据

DECLARE 
   -- 1. 定义游标(将SELECT * FROM tb_stuu 数据的查询结果放入 c_stuu 中)
   CURSOR c_stuu IS SELECT * FROM tb_stuu;
   -- 2. 定义rowtype(把抓取到的数据放入 r_stuu 中)
   r_stuu tb_stuu%ROWTYPE;
BEGIN
  OPEN c_stuu;
       -- 提取数据
       LOOP
           --fetch 提取到数据放入变量r_stuu中
         FETCH c_stuu INTO r_stuu;
         EXIT WHEN c_stuu%NOTFOUND;
         dbms_output.put_line(r_stuu.id || ' '||r_stuu.name);
       END LOOP;
  CLOSE c_stuu;
END;

SELECT * FROM tb_stuu;
SELECT * FROM tb_student;

带参数的游标
第二个例子:使用游标提取 tb_stuu 的所有数据,同时提取每个班级的学生数据
注意:传递是形参,形参是不用长度的

DECLARE
    -- 此处 stuu 表,主要充当班级表 
    -- 创建了一个游标,保存 tb_stuu 表中的所有数据
    CURSOR c_stuu IS SELECT * FROM tb_stuu;
    
    r_stuu tb_stuu%ROWTYPE;
    
    -- 此处 student 表,充当学生表
    -- 创建了一个游标,保存 tb_student 表中的所有数据
    -- 并且接收了一个参数,这个参数主要是来自 tb_stuu 表中的 id 值
    -- 用了之后,效果是把两张表绑定到一起
    CURSOR c_student(v_id tb_stuu.id%TYPE) IS 
    SELECT * FROM tb_student WHERE id = v_id;
    
    r_student tb_student%ROWTYPE;
BEGIN
  -- 外层打开 stuu 游标,也就是先使用 stuu(班级表)中的数据
  -- 会先循环一遍,一共会循环 4 次,把对应的数据抓取出来
  -- 1
  OPEN c_stuu;
       LOOP
         FETCH c_stuu INTO r_stuu;
         -- 直到 c_stuu 中的值找不到的时候,就退出了
         EXIT WHEN c_stuu%NOTFOUND;
         dbms_output.put_line('班级:' || r_stuu.id||' '||r_stuu.name);
         
         -- 内层打开 student 游标,接着需要使用 student(学生表)中的数据
         -- 也会循环,注意,外面循环一次,里面循环 5 次。
         -- 查找当前班级的学生信息 
         OPEN c_student(r_stuu.id);
              LOOP
               -- 抓取数据
                FETCH c_student INTO r_student;
                -- 直到 c_student 中的值找不到的时候,就退出了
                EXIT WHEN c_student%NOTFOUND;
                dbms_output.put_line(r_student.id||' '||r_student.name);
              END LOOP;
         CLOSE c_student;
         
       END LOOP;
  CLOSE c_stuu;
END;

练习:
使用游标提取 scott 用户的 dept 的所有数据,
同时提取每个部门的员工数据,打印在控制台

SELECT * FROM scott.dept;
SELECT * FROM scott.emp;

DECLARE
   CURSOR c_dept IS SELECT * FROM scott.dept;
   CURSOR c_emp(v_deptno scott.dept.deptno%TYPE) 
   IS SELECT * FROM scott.emp WHERE deptno = v_deptno;
BEGIN
 -- 先处理部门,因为一个部门中,可以有多个员工
  FOR r_dept IN c_dept
    LOOP
      dbms_output.put_line('部门:' || r_dept.deptno||' '||r_dept.dname);
      
      FOR r_emp IN c_emp(r_dept.deptno)
        LOOP
          dbms_output.put_line(r_emp.empno||' '||r_emp.ename||'  '||r_emp.job||'  '||r_emp.sal);
        END LOOP;
      
      dbms_output.put_line('***************************************');
      
    END LOOP;
END;

上一篇 下一篇

猜你喜欢

热点阅读