游标:用来提取多行数据
Oracle 打开一个工作区(内存区域)来保存多行查询的结果集,
游标就是给这个工作区命的名称,并能用于处理由多行查询而返回的记录行。
隐式游标: 默认的 DML 语句和 select 语句都有隐式游标。
显示游标: 开发中给工作区命名,并且可以进行操作。
%ISOPEN Boolean 游标打开,则返回True(游标打开之后,不能再次打开,游标关闭之后,不能再次关闭)
%NOTFOUND Boolean 如果最近抓取没有获得记录,返回True
%FOUND Boolean 如果最近抓取获得记录,返回True
%ROWCOUNT Number 返回到目前为止获取的记录数
使用游标的步骤:
- 定义游标 CURSOR c_tb_stuu IS SELECT * FROM tb_stuu;
- 打开游标 OPEN c_tb_stuu;
- fetch游标 FETCH c_tb_stuu INTO r_tb_stuu;
游标有个指针,默认指向第一行之上,fetch将指针向下移动,指向第N行数据,
如果有数据,NOTFOUND返回false,FOUND返回true。
如果到末尾,会一直抓取最后一条数据 - 关闭游标 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;
网友评论