SQL游标——PL/SQL教程(三)

SQL游标

/*
在执行执行增删改查语句的时候,Oracle都会开辟一块内存空间,
用来暂时存放收到SQL语句影响的数据。
这块内存空间就被称为游标区域,我们可以借助于游标来分析这些受到影响的数据
*/
/*
游标的分类:
1、隐式游标:
增删改查语句都会由隐式游标,也就是说,我们可以通过隐式游标来分析受到增删改查语句影响的数据。

2、显式游标:
在PL/SQL种执行select语句的特殊要求:
(1):select语句只能返回一条记录
(2):必须搭配使用into
也就是说:显示游标专门用来从数据库种查询多条数据的;
*/

游标的属性

/*
游标属性包括四种:
%rowcount	受SQL影响的行数
%found		boolean值,是否还有数据
%notfound	boolean值,是否已无数据
%isopen		游标是否打开
显示游标和隐式游标都有这四个属性。但是使用方法和含义却不相同。
*/

隐式游标

/*
在使用游标的时候,需要使用游标名称作为前缀。但是隐式游标没有名称,
所以在使用隐式游标的时候采取统一的一个名称SQL。
也就是说:隐式游标同意使用SQL前缀,例如:
SQL%rowcount	受SQL影响的行数
SQL%found		boolean值,是否还有数据
SQL%notfound	boolean值,是否已无数据
SQL%isopen		总是false
*/
declare
	v_count number(3);
begin
	delete from emp where deptno = 10;
	v_count :=SQL%rowcount;
	dbms_output.put_line('被删除的数据的条数是:'|| v_count);
end;

显示游标

/*
显式游标的使用:
1、可以用于暂存查询取出的多行结果,然后一行一行的处理。
2、显示游标就是专门用来查询多条数据的
3、按行处理查询返回的多行结果
4、显示游标首先将查询出的多行数据暂存在游标区域中,然后在PL/SQL中
借助循环语句手动的控制游标的多行操作,每次取出一条进行处理,直到取出
游标中所有的数据为止。

显式游标和隐式游标不同,在调用隐式游标的时候,通过SQL前缀来调用(SQL%rowcount),
而显式游标都有自己的名称,在调用时使用显示游标的名称,作为属性的前缀(游标名%rowcount)。
*/

declare
	-- 1、声明游标,一个显示游标,就是和一个有效的select语句绑死的
	 cursor cur_emp is select * from emp;
	 v_emp emp%rowtype;
begin
	-- 2、打开游标,就是执行了游标绑定的SQL语句,并且把受到影响的数据放入到了游标区域中
	open cur_emp;
	-- 3、取出游标中的一条数据装入记录类型的变量中
	fetch cur_emp into v_emp;
	-- 从记录类型的变量中取出查询数据
	dbms_output.put_line(v_emp.empno||','||v_emp.ename||','||
                         v_emp.job||','||v_emp.mgr||','||v_emp.hiredate||','||
                         v_emp.sal||','||nvl(v_emp.comm,0)||','||v_emp.deptno);
     -- 关闭游标,清空游标区域
     close cur_emp;
     
     -- 那么问题来了,我们不是说可以从显式游标中取出多条数据吗?但我们只取了一条,那是因为我们没有用循环。
end;



-- 使用loop循环和%notfound来遍历游标
declare
-- 1、声明游标,一个显示游标,就是和一个有效的select语句绑死的
	 cursor cur_emp is select * from emp;
	 v_emp emp%rowtype;
begin
	--dbms_output.put_line('查询游标的总条数'||cur_emp%rowtype);
	-- 在游标没有打开之前或者关闭之后,是无法使用的,就会导致无效的游标错误
	-- 在关闭之后,如果需要重新使用游标,需要重新打开游标
	
	-- 2、打开游标,就是执行了游标绑定的SQL语句,并且把受到影响的数据放入到了游标区域中
	open cur_emp;
	loop 
		-- 3、取出游标中的一条数据装入记录类型的变量中
        fetch cur_emp into v_emp;
        exit when cur_emp%notfound; -- 当游标中没有数据的时候,退出循环。
        dbms_output.put_line(v_emp.empno||','||v_emp.ename||','||
                             v_emp.job||','||v_emp.mgr||','||v_emp.hiredate||','||
                             v_emp.sal||','||nvl(v_emp.comm,0)||','||v_emp.deptno);

	end loop;
	dbms_output.put_line('查询游标的总条数'||cur_emp%rowcount);
	close cur_emp;
	--dbms_output.put_line('查询游标的总条数'||cur_emp%rowtype);
end;



-- 使用while循环和%found搭配使用分析游标数据
declare
 	cursor cur_emp is select * from emp;
	v_emp emp%rowtype;
begin
	open cur_emp;
	fetch cur_emp into v_emp;--取出游标中的一条数据装入记录类型的变量中
	-- 如果把这句放在while里面,那么游标里面的值就是0
	while(cur_emp%found) loop
		-- fetch cur_emp into v_emp;
		dbms_output.put_line(v_emp.empno||','||v_emp.ename||','||
                         v_emp.job||','||v_emp.mgr||','||v_emp.hiredate||','||
                         v_emp.sal||','||nvl(v_emp.comm,0)||','||v_emp.deptno);
         fetch cur_emp into v_emp;--迭代,如果没有的话,就会一直存入第一条数据,造成内容溢出。    
	end loop;
	dbms_output.put_line('查询游标的总条数'||cur_emp%rowcount);
	close cur_emp;
end;


-- 使用for循环,可以简化游标的开发,Oracle会自动的声明记录类型的变量,Oracle会自动的open,fetch、close游标。
declare
 	cursor cur_emp is select * from emp;
begin
	-- Oracle会自动的声明记录类型的变量v_emp,类型是emp%rowtype;
	-- for循环会自动 open 
	for v_emp in cur_emp loop
		dbms_output.put_line(v_emp.empno||','||v_emp.ename||','||
                         v_emp.job||','||v_emp.mgr||','||v_emp.hiredate||','||
                         v_emp.sal||','||nvl(v_emp.comm,0)||','||v_emp.deptno);
	end loop;
end;



-- 带参数的游标
/*
也就是带条件的游标,因为有时候我们不需要查询所有。
*/
declare
	cursor cur_emp(v_deptno number) is select * from emp where deptno=v_deptno;
	v_emp emp%rowtype;
begin
	open cur_emp(20);--查询20部门
	loop 
	fetch cur_emp into v_emp;
	dbms_output.put_line(v_emp.empno||','||v_emp.ename||','||
                         v_emp.job||','||v_emp.mgr||','||v_emp.hiredate||','||
                         v_emp.sal||','||nvl(v_emp.comm,0)||','||v_emp.deptno);
     	exit when cur_emp%notfound; -- 但游标中没有数据的时候,退出循环。
	end loop;
end;

使用游标更新或删除行数据

允许使用游标删除或更新活动集中的行
声明游标时必须使用 select....for update 语句

declare
	v_emp emp%rowtype;
	cursor mycur is select * from emp where deptno=20 for update;
begin
	open mycur;
	fetch mycur into v_emp;
	while mycur%found loop
		-- where current of 游标名; 对游标读取的所在行进行更新和删除
		update emp set sal = 100 where current of mycur;
		fetch mycur into v_emp;
	end loop;
	close mycur;
end;

REF游标

/*
REF 游标
*/
-- 查询所有的员工信息

declare
	-- 声明 ref 游标类型
	type myret is ref cursor;
	-- 声明ref游标类型的变量
	cur_emp myret;
	-- 声明变量
	v_emp emp%rowtype;
begin
	-- 开启 ref 游标
	open cur_emp for select * from emp;
	fetch cur_emp into v_emp;
	
	while cur_emp%found loop
		dbms_output.put_line(v_emp.empno||','||v_emp.ename||','||
                         v_emp.job||','||v_emp.mgr||','||v_emp.hiredate||','||
                         v_emp.sal||','||nvl(v_emp.comm,0)||','||v_emp.deptno);
         fetch cur_emp into v_emp;
	end loop;
	close cur_emp;
end;

猜你喜欢

转载自blog.csdn.net/Hao1999_/article/details/121438096
今日推荐