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;


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;


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;

使用游标删除数据


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;

时间: 2024-10-22 10:17:02

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编程详解》全原创(共八篇)--系列文章导航

原文:[强烈强烈推荐]<ORACLE PL/SQL编程详解>全原创(共八篇)--系列文章导航 <ORACLE PL/SQL编程详解> 系列文章目录导航 ——通过知识共享树立个人品牌. 本是成书的,但后来做其他事了,就无偿的贡献出来,被读者夸其目前为止最“实在.经典”的写ORACLE PL/SQL编程的文章-! 觉得对你有帮助,请留言与猛点推荐,谢谢. [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下) 本篇主要内容如下:第一章 PL/S

[推荐]ORACLE PL/SQL编程详解之三: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编程详解之一: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编程之四:把游标说透(

[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)

原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天才在于积累!) ——通过知识共享树立个人品牌.   继上七篇:            [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)            [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之

ORACLE PL/SQL编程详解

ORACLE PL/SQL编程详解 编程详解 SQL语言只是访问.操作数据库的语言,并不是一种具有流程控制的程序设计语言,而只有程序设计语言才能用于应用软件的开发.PL /SQL是一种高级数据库程序设计语言,该语言专门用于在各种环境下对ORACLE数据库进行访问.由于该语言集成于数据库服务器中,所以PL/SQL代码可以对数据进行快速高效的处理.除此之外,可以在ORACLE数据库的某些客户端工具中,使用PL/SQL语言也是该语言的一个特点.本章的主要内容是讨论引入PL/SQL语言的必要性和该语言的

Hadoop Hive sql语法详解

Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行,通过自己的SQL 去查询分析需要的内容,这套SQL 简称Hive SQL,使不熟悉mapreduce 的用户很方便的利用SQL 语言查询,汇总,分析数据.而mapreduce开发人员可以把己写的mapper 和reducer 作为插件来支持

图解MYSQL JOIN ON,SQL JOIN 详解,数据库sql join语句

对于SQL的Join,在学习起来可能是比较乱的.我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚.Coding Horror上有一篇文章(实在不清楚为什么Coding Horror也被墙)通过 文氏图 Venn diagrams 解释了SQL的Join.我觉得清楚易懂,转过来. 假设我们有两张表. Table A 是左边的表. Table B 是右边的表. 其各有四条记录,其中有两条记录是相同的,如下所示

PL/SQL游标

PL/SQL游标:A:分类:1:隐式游标:非用户明确声明而产生的游标. 你根本看不到cursor这个关键字.2:显示游标:用户明确通过cursor关键字来声明的游标. B:什么是隐式游标:1:什么时候产生:会在执行任何合法的SQL语句(DML---INSERT UPDATE DELETE DQL-----SELECT)中产生.他不一定存放数据.也有可能存放记录集所影响的行数.如果执行SELECT语句,这个时候游标会存放数据.如果执行INSERT UPDATE DELETE会存放记录影响的行数.C