Oracle游标 CURSOR实例详解
Posted 520gqk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle游标 CURSOR实例详解相关的知识,希望对你有一定的参考价值。
作者:gqk
游标 CURSOR:
一、游标概述:
游标(cursor)是数据库系统在内存中开设的一个数据缓冲区,存放SQL语句的执行结果。
每个游标都有一个名字,用户可以用SQL语句逐一从游标中获取记录,并赋给变量做进一步处理。
作用:用于定位结果集的行 和 遍历结果集。
二、游标分类:
- 显式游标:在前述程序中用到的SELECT...INTO...查询语句,一次只能从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标
- 隐式游标:但是如果要提取多行数据,就要由程序员定义一个显式游标,并通过与游标有关的语句进行处理。显式游标对应一个返回结果为多行多列的SELECT语句。
三:显示游标:
处理显示游标需要的四个步骤:
- 定义游标:就是定义一个游标的名称,以及与其对应的SELECT语句,形式如下
-
- CURSOR 游标名称 IS select_statement
-
- 打开游标 :open 游标变量(不能重复打开游标)
-
- 打开游标时,SELECT语句的查询结果就被传送到了游标工作区。
-
- 提取数据 :fetch 游标变量 into 变量1,变量2,……
-
- 提取操作必须在打开游标之后进行。
-
- 关闭游标:close 游标变量
显式游标打开后,必须显式地关闭。游标一旦关闭,游标占用的资源就被释放,游标变成无效,必须重新打开才能使用。
--查询输出所有员工的编号,姓名,工资:(当执行fetch时提取数据指针下移一行)
DECLARE v_empid employees.employee_id%TYPE; v_name employees.last_name%TYPE; v_salary employees.salary%TYPE; CURSOR emp_cursor IS SELECT employee_id,last_name,salary FROM employees WHERE department_id=90; BEGIN OPEN emp_cursor; FETCH emp_cursor INTO v_empid,v_name,v_salary;--默认指向第一行 FETCH emp_cursor INTO v_empid,v_name,v_salary; FETCH emp_cursor INTO v_empid,v_name,v_salary; dbms_output.put_line(‘编号:‘ || v_empid); dbms_output.put_line(‘姓名:‘ || v_name); dbms_output.put_line(‘工资:‘ || v_salary); CLOSE emp_cursor; END;
四:游标的四个属性
游标变量%found:当最近一次读记录时成功返回,则值为TRUE
游标变量%notfound:同上,求反
游标变量%isopen:判断游标是否已经打开
游标变量%rowcount:返回已从游标中读取的记录数
--查询输出所有员工的编号,姓名,工资
loop循环
DECLARE v_empid employees.employee_id%TYPE; v_name employees.last_name%TYPE; v_salary employees.salary%TYPE; CURSOR emp_cursor IS SELECT employee_id,last_name,salary FROM employees; BEGIN OPEN emp_cursor; LOOP FETCH emp_cursor INTO v_empid,v_name,v_salary; EXIT WHEN emp_cursor%NOTFOUND;--读取最后一次失败后跳出循环 dbms_output.put_line(‘编号:‘ || v_empid); dbms_output.put_line(‘姓名:‘ || v_name); dbms_output.put_line(‘工资:‘ || v_salary); dbms_output.put_line(‘--------------------‘); END LOOP; CLOSE emp_cursor; END;
while 循环
DECLARE v_empid employees.employee_id%TYPE; v_name employees.last_name%TYPE; v_salary employees.salary%TYPE; CURSOR emp_cursor IS SELECT employee_id,last_name,salary FROM employees; BEGIN OPEN emp_cursor; FETCH emp_cursor INTO v_empid,v_name,v_salary; WHILE emp_cursor%FOUND LOOP dbms_output.put_line(‘编号:‘ || v_empid); dbms_output.put_line(‘姓名:‘ || v_name); dbms_output.put_line(‘工资:‘ || v_salary); dbms_output.put_line(‘--------------------‘); FETCH emp_cursor INTO v_empid,v_name,v_salary; END LOOP; CLOSE emp_cursor; END;
--查询输出所有员工的编号,姓名,工资(PLSQL表类型)
DECLARE TYPE emp_table_type IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER; e emp_table_type; CURSOR emp_cursor IS SELECT * FROM employees; BEGIN OPEN emp_cursor; FETCH emp_cursor BULK COLLECT INTO e; FOR i IN 1..e.COUNT LOOP dbms_output.put_line(‘编号:‘ || e(i).employee_id); dbms_output.put_line(‘姓名:‘ || e(i).last_name); dbms_output.put_line(‘工资:‘ || e(i).salary); dbms_output.put_line(‘--------------------‘); END LOOP; CLOSE emp_cursor; END;
--查询输出所有员工的编号,姓名,工资(通过limit控制提取的数据量)每次提取6条数据
DECLARE TYPE emp_table_type IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER; e emp_table_type; v_count NUMBER := 1; CURSOR emp_cursor IS SELECT * FROM employees; BEGIN OPEN emp_cursor; LOOP dbms_output.put_line(‘第‘ || v_count || ‘次FETCH‘); FETCH emp_cursor BULK COLLECT INTO e LIMIT 6; FOR i IN 1..e.COUNT LOOP dbms_output.put_line(‘编号:‘ || e(i).employee_id); dbms_output.put_line(‘姓名:‘ || e(i).last_name); dbms_output.put_line(‘工资:‘ || e(i).salary); dbms_output.put_line(‘--------------------‘); END LOOP; EXIT WHEN emp_cursor%NOTFOUND; v_count := v_count + 1; END LOOP; CLOSE emp_cursor; END;
--查询输出某个部门的员工的编号,姓名,工资(参数化游标)
DECLARE v_empid employees.employee_id%TYPE; v_name employees.last_name%TYPE; v_salary employees.salary%TYPE; CURSOR emp_cursor(p_deptid employees.department_id%TYPE) IS SELECT employee_id,last_name,salary FROM employees WHERE department_id=p_deptid; BEGIN OPEN emp_cursor(50); LOOP FETCH emp_cursor INTO v_empid,v_name,v_salary; EXIT WHEN emp_cursor%NOTFOUND; dbms_output.put_line(‘编号:‘ || v_empid || ‘,姓名:‘ || v_name || ‘,工资:‘ || v_salary); END LOOP; CLOSE emp_cursor; dbms_output.put_line(‘----------------------‘); OPEN emp_cursor(90); LOOP FETCH emp_cursor INTO v_empid,v_name,v_salary; EXIT WHEN emp_cursor%NOTFOUND; dbms_output.put_line(‘编号:‘ || v_empid || ‘,姓名:‘ || v_name || ‘,工资:‘ || v_salary); END LOOP; CLOSE emp_cursor; END;
五:游标for循环:
PL/SQL中提供了游标for循环语句,可以自动的执行游标的open,fetch,close语句和循环语句的功能,当进入循环时,游标for循环语句自动打开游标,并提取第一行数据,提取
提取完成后自动进入下一个提取,提取完成后自动关闭游标:
--查询输出所有员工的编号,姓名,工资
DECLARE CURSOR emp_cursor IS SELECT * FROM employees; BEGIN FOR e IN emp_cursor LOOP dbms_output.put_line(e.employee_id||‘,‘||e.last_name||‘,‘||e.salary); END LOOP; END;
--查询输出所有员工的编号,姓名,工资(带参数)
DECLARE CURSOR emp_cursor(p_deptid employees.department_id%TYPE) IS SELECT * FROM employees WHERE department_id=p_deptid; BEGIN FOR e IN emp_cursor(90) LOOP dbms_output.put_line(e.employee_id||‘,‘||e.last_name||‘,‘||e.salary); END LOOP; END;
--查询输出所有员工的编号,姓名,工资(最精简写法)
DECLARE BEGIN FOR e IN (SELECT * FROM employees) LOOP dbms_output.put_line(e.employee_id||‘,‘||e.last_name||‘,‘||e.salary); END LOOP; END;
--输出每个部门的部门编号,部门名称以及这个部门的下属员工的编号,姓名,工资
/*
10 nec
100,tom,2400
101,jack,17000
20 ge
102,rose,2600
xxx,xxx,xxx
xxx,xxx,xxx
40 hsw
xxx,xxx,xxx
*/
DECLARE CURSOR dept_cursor IS SELECT * FROM departments; CURSOR emp_cursor(p_deptid NUMBER) IS SELECT * FROM employees WHERE department_id=p_deptid; BEGIN FOR d IN dept_cursor LOOP dbms_output.put_line(d.department_id || ‘ ‘ || d.department_name); FOR e IN emp_cursor(d.department_id) LOOP dbms_output.put_line(‘ ‘ || e.employee_id || ‘,‘ || e.last_name || ‘,‘ || e.salary); END LOOP; END LOOP; END;
隐式游标:固定名称SQL
SQL%FOUND:如果操作有影响的行,就为TRUE,否则为FALSE
SQL%NOTFOUND:求反
SQL%ISOPEN:在隐式游标中,取值永远为FALSE
SQL%ROWCOUNT:操作影响的行数
*/
--如果有员工被更新,输出“更新成功,有XX个员工被更新”
--如果没有任何员工被更新,输出“这个部门不存在,没有任何员工被更新”
DECLARE v_deptid NUMBER := &input; BEGIN UPDATE employees SET salary = salary + 1 WHERE department_id = v_deptid; IF SQL%FOUND THEN dbms_output.put_line(‘更新成功,有‘ || SQL%ROWCOUNT || ‘个员工被更新‘); ELSE dbms_output.put_line(‘这个部门不存在,没有任何员工被更新‘); END IF; COMMIT; END;
--通过游标去更新员工的工资,如果工资低于5000块,则把工资改为5000
DECLARE CURSOR emp_cursor IS SELECT * FROM new_emp FOR UPDATE; BEGIN FOR e IN emp_cursor LOOP IF e.salary<5000 THEN UPDATE new_emp SET salary=5000 WHERE CURRENT OF emp_cursor; END IF; END LOOP; END;
--通过游标删除工资=5000的员工
DECLARE CURSOR emp_cursor IS SELECT * FROM new_emp FOR UPDATE; BEGIN FOR e IN emp_cursor LOOP IF e.salary=5000 THEN DELETE FROM new_emp WHERE CURRENT OF emp_cursor; END IF; END LOOP; END;
--游标变量(动态游标)
--用户输入一个字母,输入E,输出所有员工姓名,如果输入D,输出所有部门的名称
DECLARE v_cmd CHAR(1) := ‘&input‘; v_name VARCHAR2(50); --声明自定义的游标变量类型 --TYPE c_type IS REF CURSOR; --声明游标变量 --c c_type; c SYS_REFCURSOR;--代替TYPE c_type IS REF CURSOR BEGIN IF v_cmd=‘E‘ THEN dbms_output.put_line(‘员工姓名‘); OPEN c FOR SELECT last_name FROM employees; ELSIF v_cmd=‘D‘ THEN dbms_output.put_line(‘部门名称‘); OPEN c FOR SELECT department_name FROM departments; ELSE dbms_output.put_line(‘输入无效‘); RETURN; END IF; LOOP FETCH c INTO v_name; EXIT WHEN c%NOTFOUND; dbms_output.put_line(v_name); END LOOP; CLOSE c; END;
以上是关于Oracle游标 CURSOR实例详解的主要内容,如果未能解决你的问题,请参考以下文章