游标是Oracle服务器为SQL语句建立的一个私有的SQL工作区。
显示游标:由编程者明确指定。 隐式游标:在缺省情况下,Oracle服务器以隐式游标来编译和执行SQL。
使用SQL游标属性,可以测试SQL语句的输出。
游标属性说明SQL%ROWCOUNT最后依次执行的SQL语句所影响到的数据行(一个整数值),几条数据受影响就返回几SQL%FOUND一个Boolean值,如果最后一次SQL语句影响到了一条或多条记录,则该值为true,否则为falseSQL%NOFOUND一个Boolean值,如果最后一次SQL语句影响到了一条或多条记录,则该值为false,否则为trueSQL%ISOPEN一个Boolean值,如果游标是打开的,则返回true,否则返回false;对于隐式游标永远为false,因为语句块执行完毕后,游标自动关闭①declare:创建一个命名的SQL数据区 ②open:打开活动数据集 ③fetch:将当前行载入到变量中 ④判断:对当前行进行检验,如果有数据行,继续执行第三步;如果没有数据行,跳到下一步。 ⑤close:释放活动数据集
语法:
CURSOR cursor_name IS select statement;注意: 游标中没有into 查询中可以使用order by
例子:
declare cursor emp_cursor is select empno, ename from emp; cursor dept_cursor is select * from dept where deptno=10; begin ....例子:
if not emp_cursor%isopen then open emp_cursor; end if; loop fetch emp_cursor...①打开游标
open cursor_name;打开游标的作用是执行查询,并获得活动数据集。 查询不返回数据集是正常的,这并不是一个异常。 进行一次fetch操作后,使用游标属性来检验输出。
②从游标中fetch数据
fetch cursor_name into v_empno, v_ename;将游标的当前行取到变量中去。 变量应与游标的各个变量一一对应。 检验游标中是否存在数据行值。
③关闭游标
close cursor_name;结束处理后,关闭游标。 如果需要,可以重新打开数据行 一旦一个游标被关闭,就不能从游标中获取数据
for循环游标是处理显示游标的捷径 open、fetch、close都暗含在语句里面 寻访数据行的记录是隐士声明的
语法:
FOR record_name IN cursor_name LOOP statement1; statement2; ... END LOOP;员工表:
enamesal张三6000李四5000王五5000赵六4000刘七3000①查出员工工资,降序排列,用户输入4,查出前四个人的工资,然后用游标把查出来的信息插入top_sales表中。
declare cursor emp_cursor is select * from (select ename, sal from emp order by sal desc) where rownum<=&rownum; top_emp emp_cursor %rowtype; begin open emp_cursor ; loop fetch emp_cursor into top_emp ; exit when emp_cursor%notfound; insert into top_sales values(top_emp.ename, top_emp.sal ); end loop; close emp_cursor ; end;②查出员工工资,降序排列,用户输入4,查出工资数目前四的人,然后用游标把查出来的信息插入top_sales表中。
declare cursor emp_cursor is select * from (select ename, sal from emp order by sal desc) where rownum<=&rownum; top_emp emp_cursor %rowtype; same_sal emp.sal%type; same_ename emp.ename%type; cursor same_emp_cursor is select ename, sal from emp where sal=same_sal and ename<>same_ename ; same_emp same_emp_cursor %rowtype; begin open emp_cursor ; loop fetch emp_cursor into top_emp ; exit when emp_cursor %notfound; insert into top_sales values(top_emp.ename, top_emp.sal); same_sal :=top_emp.sal; same_ename :=top_emp.ename; open same_emp_cursor ; loop fetch same_emp_cursor into same_emp ; exit when same_emp_cursor %notfound; insert into top_sales values(same_emp.ename, same_emp.sal ); end loop; close same_emp_cursor ; end loop; close emp_cursor ; end;使用for update语句使得事务在运行期间,其他事务对同一数据的访问被拒绝。 通俗的讲就是锁表。 解释一下:在企业级开发中,会把oracle数据库装在公司服务器上,表也建在服务器上,所有的开发者通过链接服务器地址去操作数据库和数据库的表、视图等。如果一个开发者A对emp表进行for update操作,其他开发者如果想要对emp表进行update或者delete的时候,会陷入等待。直到开发者A对emp表进行commit操作之后,emp表的update个delete才能正常进行。
1.select * from Table1 for update 锁定表天、Table1的所有行,其他用户只能读不能写
2 select * from Table1 where id = 1 for update 只锁定表Table1的id=1的行
3 select * from Table1 a join Table2 b on a.id=b.id for update 锁定两个表的所有记录
4 select * from Table1 a join Table2 b on a.id=b.id where a.id = 10 for update 锁定两个表的中满足条件的行
5. select * from Table1 a join Table2 b on a.id=b.id where a.id = 10 for update of a.id 只锁定Table1中满足条件的行
划重点: for update 是把所有的表都锁点 for update of 根据of 后表的条件锁定相对应的表。
讲的详细点: 开发者A:select * from emp where empno=6666 for update; ① 若开发者B:select * from emp where empno=1111 for update;此时不会阻塞,但是会显示no rows selected。事实上empno=1111的员工是存在的。 ②若开发者B:select * from emp where empno=6666 for update;此时会陷入阻塞状态,只有开发者A执行commit后,B才会从阻塞状态出来。 ③ 若开发者B:select * from emp for update;也会陷入阻塞,只有开发者A执行commit后,B才会从阻塞状态出来。 ④开发者B:select * from emp for update nowait;程序正常执行。 ⑤开发者B:select * from emp where empno=6666 for update nowait;程序正常执行。 ⑥开发者B:select * from emp where empno=6666 for update wait 3此时程序会在3秒后报错:ORA-30006: resource busy; acquire with WAIT timeout expired
当你要使用游标进行更新和删除操作时,则需要使用where current of 语句,这个是标示出当前游标的位置. 例子:
declare cursor sal_cursor is select sal from emp where deptno=30; for update of sal nowait; begin for emp_record in sal_cursor loop update emp set sal=emp_record.sal*1.1 where current of sal_cursor; end loop; commit; end;例子:查询同一个部门员工大于5为的员工信息。
declare cursor emp_cursor is select t1.empno, t1.ename, t1.job, t1.sal, t2.deptno from emp t1,(select deptno,count(*) cols from emp group by deptno) t2 where t1.deptno=t2.deptno and t2.cols>5; emp_info emp_cursor%rowtype; begin open emp_cursor ; loop fetch emp_cursor into emp_info ; exit when emp_cursor%notfound; dbms_output.put_line(emp_info.empno || ', '|| emp_info.ename || ', '||emp_info.job || ', '||emp_info.sal ); end loop; close emp_cursor; end;①使用游标从dept表中提出部门编号。将这个参数传递到另一个游标中,取出emp表中工作在该部门的员工信息。
declare cursor dept_cursor is select deptno from dept; dept_rec number(3); cursor emp_cursor(v_deptno number) is select empno, ename, sal, job, hiredate from emp where deptno=v_deptno; emp_rec emp_cursor%rowtype; begin open dept_cursor ; loop fetch dept_cursor into dept_rec; exit when dept_cursor%notfound; for emp_rec in emp_cursor(dept_rec) loop dbms_output.put_line(emp_rec.empno || ', '|| emp_rec.ename || ', '||emp_rec.sal || ', '||emp_rec.job || ', '||emp_rec.hiredate ); end loop; end loop; end;②使用游标来emp表中员工的工资,工资大于等于1500的增加20%,小于1500的增加30%。
declare cursor sal_cursor is select sal from emp for update of sal nowait; emp_record sal_cursor%rowtype; begin for emp_record in sal_cursor loop if emp_record.sal >=1500 then update emp set sal = 1.2*emp_record.sal where current of sal_cursor; elsif emp_record.sal<1500 then update emp set sal = 1.3*emp_record.sal where current of sal_cursor; end if; end loop; end;