PL/SQL游标详解
刚打开游标的时候,是位于一个空行,要用fetch into 才能到第一行。
只是要注意用更新游标的时候,不能在游标期间commit. 否则会报
ORA-01002: fetch out of sequence
就是COMMIT;导致错误
在打开有for update的cursor时,系统会给取出的数据加上排他锁(exclusive),
这样在这个锁释放前其他用户不能对这些记录作update、delete和加锁。
而我一旦执行了commit,锁就释放了,游标也变成无效的,再去fetch数据时就出现错误了。
因而要把commit放在循环外,等到所有数据处理完成后再commit,然后关闭cursor
隐含游标
--------
又名SQL游标,用于处理单行select into 和 DML语句。
SQL%ISOPEN SQL%FOUND SQL%NOTFOUND SQL%ROWCOUNT
显示游标
--------
用户处理select语句返回的多行数据。
select语句返回多行数据处理方式:[1]显示游标;[2]select ... bulk collect into 集合变量...;
【1】显示游标属性
[1] %ISOPEN 检测游标是否打开。
[2] %FOUND 检测游标结果集是否存在数据。
[3] %NOTFOUND 是否不存在数据。
[4] %ROWCOUNT 游标已提取的实际行数。
【2】使用显示游标
[1] 定义游标
CURSOR cursor_name IS select_statement;
[2] 打开游标
OPEN cursor_name;
[3] 提取数据
FECTH cursor_name INTO variable,...;
[4] 关闭数据
CLOSE cursor_name;
使用标量变量:
-------------
- DECLARE
- Cursor emp_cur IS select ename,sal from emp order by empno;
- v_ename emp.ename%TYPE;
- v_sal emp.sal%TYPE;
- BEGIN
- IF NOT emp_cur%ISOPEN THEN
- OPEN emp_cur;
- DBMS_OUTPUT.PUT_LINE('打开游标');
- END IF;
- NULL;
- LOOP
- FETCH emp_cur INTO v_ename,v_sal;
- EXIT WHEN emp_cur%NOTFOUND;
- DBMS_OUTPUT.PUT_LINE('用户名:'||v_ename||',工资:'||v_sal);
- END LOOP;
- NULL;
- IF emp_cur%ISOPEN THEN
- CLOSE emp_cur;
- DBMS_OUTPUT.PUT_LINE('关闭游标');
- END IF;
- END;
使用PLSQL记录变量
-----------------
- DECLARE
- Cursor emp_cur IS select ename,sal from emp order by empno;
- emp_record emp_cur%ROWTYPE;
- BEGIN
- IF NOT emp_cur%ISOPEN THEN
- OPEN emp_cur;
- DBMS_OUTPUT.PUT_LINE('打开游标');
- END IF;
- NULL;
- LOOP
- FETCH emp_cur INTO emp_record;
- EXIT WHEN emp_cur%NOTFOUND;
- DBMS_OUTPUT.PUT_LINE('用户名:'||emp_record.ename||',工资:'||emp_record.sal);
- END LOOP;
- NULL;
- IF emp_cur%ISOPEN THEN
- CLOSE emp_cur;
- DBMS_OUTPUT.PUT_LINE('关闭游标');
- END IF;
- END;
使用PLSQL集合变量
-----------------
- DECLARE
- Cursor emp_cur IS select ename,sal from emp order by empno;
- TYPE emp_table_type IS TABLE OF emp_cur%ROWTYPE INDEX BY BINARY_INTEGER;
- emp_table emp_table_type;
- i number;
- BEGIN
- i := 1;
- IF NOT emp_cur%ISOPEN THEN
- OPEN emp_cur;
- DBMS_OUTPUT.PUT_LINE('打开游标');
- END IF;
- NULL;
- LOOP
- FETCH emp_cur INTO emp_table(i);
- EXIT WHEN emp_cur%NOTFOUND;
- DBMS_OUTPUT.PUT_LINE('用户名:'||emp_table(i).ename||',工资:'||emp_table(i).sal);
- i := i + 1;
- END LOOP;
- NULL;
- IF emp_cur%ISOPEN THEN
- CLOSE emp_cur;
- DBMS_OUTPUT.PUT_LINE('关闭游标');
- END IF;
- END;
【3】循环游标
FOR record_name IN cursor_name|select_statement LOOP
statement;
....
END LOOP;
使用循环游标
------------
- declare
- cursor emp_cusor is select ename,sal from emp where deptno = &no order by empno;
- begin
- for emp_record in emp_cusor loop
- dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
- end loop;
- end;
- begin
- for emp_record in (select ename,sal from scott.emp where deptno = &no order by empno) loop
- dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
- end loop;
- end;
【4】参数游标
CURSOR cursor_name(parameter_name datatype) IS select_statement; --只能制定类型,不能指定具体大小
OPEN cursor_name(参数值);
FECTH cursor_name INTO variable,...;
CLOSE cursor_name;
使用游标参数
------------
示例1:
------
- declare
- cursor emp_cursor(v_depnto number) is select ename,sal from scott.emp where deptno = v_depnto order by empno;
- emp_record emp_cursor%rowtype;
- v_dno number;
- begin
- v_dno := &no;
- if not emp_cursor%isopen then
- open emp_cursor(v_dno);
- end if;
- null;
- loop
- fetch emp_cursor into emp_record;
- exit when emp_cursor%notfound;
- dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
- end loop;
- null;
- if emp_cursor%isopen then
- close emp_cursor;
- end if;
- end;
示例2
-----
- declare
- cursor emp_cursor(v_depnto number) is select ename,sal from scott.emp where deptno = v_depnto order by empno;
- v_dno number;
- begin
- v_dno := &no;
- for emp_record in emp_cursor(v_dno) loop
- dbms_output.put_line('姓名:'||emp_record.ename||',工资:'||emp_record.sal);
- end loop;
- end;
【5】更新、删除游标行
- CURSOR cursor_name IS select_statement
- FOR UPDATE [OF column_reference] [NOWAITE]; -- OF子句指定对特定表加锁。
- UPDATE table_name SET column=.. WHERE CURRENT OF cursor_name;
- DELETE table_name WHERE CURRENT OF cursor_name;
使用游标更新数据
----------------
- declare
- cursor test_cursor is select empno,ename,sal,deptno from scott.test for update;
- test_record test_cursor%rowtype;
- v_deptno number;
- v_sal test.sal%type;
- begin
- v_deptno := &no;
- if not test_cursor%isopen then
- open test_cursor;
- end if;
- loop
- fetch test_cursor into test_record;
- exit when test_cursor%notfound;
- dbms_output.put_line('姓名:'||test_record.ename||',旧工资:'||test_record.sal);
- if test_record.deptno = v_deptno then
- update scott.test set sal=2*sal where current of test_cursor;
- else
- update scott.test set sal=3*sal where current of test_cursor;
- end if;
- end loop;
- close test_cursor;
- end;
- declare
- cursor test_cursor is select empno,ename,sal,deptno from scott.test for update;
- v_deptno NUMBER:=&dno;
- begin
- for test_record in test_cursor loop
- if test_record.deptno = v_deptno then
- dbms_output.put_line('姓名:'||test_record.ename||',旧工资:'||test_record.sal);
- update scott.test set sal = sal*1.5 where current of test_cursor;
- end if;
- end loop;
- end;
表test换成emp出现ORA-01410: 无效的 ROWID错误,什么原因???
使用游标删除数据
----------------
- declare
- cursor test_cursor(v_deptno number) is select deptno,empno,ename,comm from scott.test where deptno = v_deptno for update;
- v_dno test.deptno%type := &dno;
- begin
- for test_record in test_cursor(v_dno) loop
- if test_record.comm is null then
- dbms_output.put_line('用户名:'||test_record.ename||'部门:'||test_record.deptno);
- delete from scott.test where current of test_cursor;
- end if;
- end loop;
- end;
【6】游标变量
指向内存地址的指针。可以在打开游标时指定其所对应的SELECT语句,实现动态游标。
[1]定义REF CURSOR类型和游标变量:
Type ref_type_name IS REF CURSOR [RETURN return_type --必须是PL/SQL记录类型];
说明:如果指定RETURN子句,那么在打开游标时SELECT语句的返回结果必须与RETURN子句所指定的记录类型匹配。
cursor_variable ref_type name;
SYS_REFCURSOR
[2]打开游标,指定对应的SELECT语句:
OPEN cursor_variable FOR select_statement;
[3]提取数据
FETCH cursor_variable INTO variable1,variable,...;
[4]关闭游标
CLOSE cursor_variable;
不使用RETURN子句
----------------
- DECLARE
- TYPE ref_type_table IS REF CURSOR;
- v_cursor ref_type_table;
- emp_record emp%rowtype;
- BEGIN
- OPEN v_cursor FOR select * from emp where deptno=&no;
- LOOP
- FETCH v_cursor INTO emp_record;
- EXIT WHEN v_cursor%NOTFOUND;
- dbms_output.put_line('员工号:'||emp_record.ename||'部门号:'||emp_record.deptno);
- END LOOP;
- CLOSE v_cursor;
- END;
使用RETURN子句
--------------
- DECLARE
- emp_record emp%rowtype;
- TYPE ref_type_table IS REF CURSOR RETURN emp%rowtype;
- v_cursor ref_type_table;
- BEGIN
- OPEN v_cursor FOR select * from emp where deptno=&no;
- LOOP
- FETCH v_cursor INTO emp_record;
- EXIT WHEN v_cursor%NOTFOUND;
- dbms_output.put_line('员工号:'||emp_record.ename||'部门号:'||emp_record.deptno);
- END LOOP;
- CLOSE v_cursor;
- END;
- DECLARE
- Type emp_record_type IS RECORD(
- ename emp.ename%TYPE,
- salary emp.sal%TYPE,
- deptno emp.deptno%TYPE);
- emp_record emp_record_type;
- TYPE ref_type_table IS REF CURSOR RETURN emp_record_type;
- v_cursor ref_type_table;
- BEGIN
- OPEN v_cursor FOR select ename,sal,deptno from emp where deptno=&no;
- LOOP
- FETCH v_cursor INTO emp_record;
- EXIT WHEN v_cursor%NOTFOUND;
- dbms_output.put_line('员工号:'||emp_record.ename||',部门号:'||emp_record.deptno||',工资:'||emp_record.salary);
- END LOOP;
- CLOSE v_cursor;
- END;
【7】使用游标批量获取
FETCH ... BULK COLLECT INTO ...[LIMIT row_number];
不限制行数
----------
- DECLARE
- CURSOR emp_cursor(v_deptno number) IS SELECT * FROM EMP WHERE deptno = v_deptno;
- TYPE type_emp_table IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
- emp_table type_emp_table;
- v_dno emp.deptno%TYPE;
- BEGIN
- v_dno := &no;
- OPEN emp_cursor(v_dno);
- FETCH emp_cursor BULK COLLECT INTO emp_table;
- CLOSE emp_cursor;
- FOR i IN 1..emp_table.COUNT LOOP
- dbms_output.put_line('员工号:'||emp_table(i).ename||'工资:'||emp_table(i).sal);
- END LOOP;
- CLOSE emp_cursor;
- END;
限制行数
--------
- DECLARE
- CURSOR emp_cursor(v_deptno number) IS SELECT * FROM EMP WHERE deptno = v_deptno;
- TYPE type_emp_table IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
- emp_table type_emp_table;
- v_dno emp.deptno%TYPE;
- BEGIN
- v_dno := &no;
- OPEN emp_cursor(v_dno);
- FETCH emp_cursor BULK COLLECT INTO emp_table LIMIT &2;
- CLOSE emp_cursor;
- FOR i IN 1..emp_table.COUNT LOOP
- dbms_output.put_line('员工号:'||emp_table(i).ename||'工资:'||emp_table(i).sal);
- END LOOP;
- CLOSE emp_cursor;
- END;
【8】使用CURSOR表达式
作用嵌套游标。
- DECLARE
- CURSOR dept_emp_cursor(v_deptno number) IS
- SELECT dname,cursor(SELECT * FROM emp e WHERE e.deptno = d.deptno)
- FROM dept d WHERE deptno = v_deptno;
- TYPE emp_cursor_type IS REF CURSOR;
- emp_cursor emp_cursor_type;
- emp_record emp%ROWTYPE;
- v_name dept.dname%TYPE;
- v_dno emp.deptno%TYPE;
- BEGIN
- v_dno := &no;
- OPEN dept_emp_cursor(v_dno);
- loop
- FETCH dept_emp_cursor INTO v_name,emp_cursor;
- EXIT WHEN dept_emp_cursor%NOTFOUND;
- dbms_output.put_line('部门名称:'||v_name);
- LOOP
- FETCH emp_cursor INTO emp_record;
- EXIT WHEN emp_cursor%NOTFOUND;
- dbms_output.put_line('员工名称:'||emp_record.ename||',工资:'||emp_record.sal);
- END LOOP;
- end loop;
- CLOSE dept_emp_cursor;
- END;
转自:http://hi.baidu.com/tangwei%5Fbd/blog/item/f4adbe02e578391b738b6533.html
PL/SQL游标详解的更多相关文章
- ORACLE PL/SQL编程详解
ORACLE PL/SQL编程详解 编程详解 SQL语言只是访问.操作数据库的语言,并不是一种具有流程控制的程序设计语言,而只有程序设计语言才能用于应用软件的开发.PL /SQL是一种高级数据库程序设 ...
- [强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)
原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天 ...
- [推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆)
原文:[推荐]ORACLE PL/SQL编程详解之三:PL/SQL流程控制语句(不给规则,不成方圆) [推荐]ORACLE PL/SQL编程详解之三: PL/SQL流程控制语句(不给规则,不成方圆) ...
- 【强烈强烈推荐】《ORACLE PL/SQL编程详解》全原创(共八篇)--系列文章导航
原文:[强烈强烈推荐]<ORACLE PL/SQL编程详解>全原创(共八篇)--系列文章导航 <ORACLE PL/SQL编程详解> 系列文章目录导航 ——通过知识共享树立个人 ...
- [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)
原文:[推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下) [推荐]ORACLE PL/SQL编程详解之一: PL/SQL 程序设计简介(千里之行,始于足下 ...
- [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)
原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) [顶]ORACLE PL/SQL编程详解之二: PL/SQL块结构和组成元素(为山九仞,岂一日 ...
- ORACLE PL/SQL编程详解(转)
原帖地址:http://blog.csdn.net/chenjinping123/article/details/8737604 ORACLE PL/SQL编程详解 SQL语言只是访问.操作数据库的语 ...
- Mysql高手系列 - 第19篇:mysql游标详解,此技能可用于救火
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第19篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...
- Hive笔记--sql语法详解及JavaAPI
Hive SQL 语法详解:http://blog.csdn.net/hguisu/article/details/7256833Hive SQL 学习笔记(常用):http://blog.sina. ...
随机推荐
- DedeCMS V5.7开启memcache缓存的方法配置说明
一.安装Memcache服务:1.1.linux下的Memcache安装:-------------------------1. 下载 memcache的linux版本,注意 memcached 用 ...
- requests爬取网页的通用框架
概述 代码编写完成时间:2017.12.28 写文章时间:2017.12.29 看完中国大学MOOC上的爬虫教程后,觉得自己之前的学习完全是野蛮生长,决定把之前学的东西再梳理一遍,主要是觉得自己写的程 ...
- 4.1 State Snapshot Transfer
摘要: 出处:黑洞中的奇点 的博客 http://www.cnblogs.com/kelvin19840813/ 您的支持是对博主最大的鼓励,感谢您的认真阅读.本文版权归作者所有,欢迎转载,但请保留该 ...
- vue实现登录后跳转到之前的页面
在开发中我们经常遇到这样的需求,需要用户直接点击一个链接进入到一个页面,用户点击后链接后会触发401拦截返回登录界面,登录后又跳转到链接的页面而不是首页,这种问题该如何去做呢? 先说一下我们需要用到的 ...
- Vue 爬坑之路(三)—— 使用 vue-router 跳转页面
使用 Vue.js 做项目的时候,一个页面是由多个组件构成的,所以在跳转页面的时候,并不适合用传统的 href,于是 vue-router 应运而生. 官方文档: https://router.vue ...
- Python(一)字符串用法
一.程序输出 :print 在Python2.X中,print 的用法是 : print "hello word! " 在Python3.X中,print作为函数的方式出现,用法: ...
- mysql加锁读
Locking Reads 在同一个事务中,如果你先查询数据,随后对相关数据进行插入或修改,那么在标准的SLELECT中不会给出足够的保护.在你查询期间另一个事务可以更新或者删除相同的行.InnoDB ...
- FFmpeg编译iOS静态库
第一步:下载gas-preprocessor 1.1 下载https://github.com/libav/gas-preprocessor 1.2 拷贝 gas-preprocessor.pl 到 ...
- Java框架之Hibernate(三)
本文主要讲解: 1 级联 cascade 关键字 2 级联删除 3 inverse 关键字 4 懒加载 5 缓存的模拟 6 Hibernate 的一级缓存 7 Hibernate 的二级缓存 一.级联 ...
- Java学习笔记8(面向对象一:概念、private)
面向过程的思想:遇到问题,想,我该怎么解决这个问题?然后一步一步解决 面向对象的思想:遇到一件事的时候,思考,我该让谁来做,至于他怎样去做,不是我需要考虑的事情,只要最后做好就行 实际举例:我们要组装 ...