一、游标
游标的使用可以让用户像操作数据一样操作查询出来的数据集,它提供了一种从集合性质的结果中提取单条记录的手段
游标可以形象的看成一个变动的光标。它实际上是一个指针,它在一段Oracle存放数据查询结果集或数据操作结果集的内存中,可以指向结果集中的任何一条记录。
游标的种类:
- 静态游标:显式游标和隐式游标
- REF游标
1、显示游标
在使用之前必须有着明确的游标声明和定义,定义会关联数据查询语句,通常会返回一行或多行。打开游标后,用户可以利用游标的位置对结果集进行检索,使之返回单一的行记录。关闭游标后不能再对结果集进行任何操作。
使用步骤:
- 声明游标
- 打开游标
- 读取数据
- 关闭游标
游标属性:
- %ISOPEN:用于判断游标是否打开。打开返回TRUE
- %FOUND:用于检测行数据是否有效。有效返回TRUE
- %NOTFOUND: 于%FOUND 相反,没有提取出数据返回TRUE,否则返回FALSE
- %ROWCOUNT:累计到当前为止使用FETCH提取数据的行数。
-- 1、声明游标 declare cursor cur_emp is select * from emp where sal>2000; cursor cur_dept is select * from dept; v_emp emp%rowtype; v_dep dept%rowtype; begin delete from emp_temp; commit; -- 2、使用游标 open cur_emp; loop -- 3、读取数据 fetch cur_emp into v_emp; if cur_emp%found then insert into emp_temp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(v_emp.empno,v_emp.ename,v_emp.job,v_emp.mgr,v_emp.hiredate,v_emp.sal,v_emp.comm,v_emp.deptno); else dbms_output.put_line('一共插入'||cur_emp%rowcount||'条记录'); exit; end if; end loop ; commit; -- 4、关闭游标 close cur_emp; open cur_dept; loop fetch cur_dept into v_dep; if cur_dept%found then update emp_temp set dname=v_dep.dname where deptno=v_dep.deptno; dbms_output.put_line('部门'||v_dep.deptno||'更新结束,名称'||v_dep.dname||'共'||sql%rowcount||'条记录'); else exit; end if; end loop; update emp_temp set sal=sal*1.1 where dname='RESEARCH'; dbms_output.put_line(sql%rowcount||'个员工的工资进行了下调'); commit; end
2、隐式游标
当运行SELECT或DML语句时,PL/SQL会打开一个隐式游标
- 隐式游标由PL/SQL自动管理。
- 隐式游标的默认名称是SQL。
- SELECT或DML操作产生隐式游标。
- 隐式游标的属性始终是最新执行的SQL语句的。
二、存储过程定义
存储过程就是一段存储在数据库中执行某种功能的程序,其中包含一条或多条SQL语句的PL/SQL代码块。可以在Java、C#编程语言中调用。
存储过程的作用:
- 简化复杂的操作
- 增加数据的独立性
- 提高安全性
- 提高性能
存储过程调用方法:
- exec pro_name(参数1..);
- call pro_name(参数1..);
1. 但是exec是sqlplus命令,只能在sqlplus中使用;call为SQL命令,没有限制.
2. 存储过程没有参数时,exec可以直接跟过程名(可以省略()),但call则必须带上()
三、无参存储过程
将EMP表中工资最低的3个员工的工资加100元。 create or replace procedure testPro1 is begin update emp set sal=sal+100 where empno in ( select empno from (select empno from emp order by sal ) where rownum<4 ); commit; end testPro1;
按照不同的部门将EMP表中员工的信息输出。 create or replace procedure testPro2 is --查询出emp表中所有的dept cursor cur_deptno is select deptno from emp group by deptno; v_deptno emp.deptno%type; v_dname dept.dname%type; begin open cur_deptno; loop fetch cur_deptno into v_deptno; exit when cur_deptno%notfound; --deptno->dname select dname into v_dname from dept where deptno=v_deptno; if sql%found then dbms_output.put_line('-------------'||v_dname||'-------------'); end if; --简写游标(注意这里的sql语句后不需要;)输出部门下员工信息 for v_emp in( select * from emp where deptno=v_deptno ) loop dbms_output.put_line(v_emp.ename||' '||v_emp.job||' '||v_emp.sal); end loop; end loop; close cur_deptno; end testPro2;
四、带参存储过程
练习:根据输入的部门名称,搜索该部门下员工,并将员工信息打印到屏幕. create or replace procedure testpro4(p_dname in varchar2) is v_deptno emp.deptno%type; begin select deptno into v_deptno from dept where dname=p_dname; if sql%found then dbms_output.put_line('---------------'||p_dname||'---------------'); for cur_emp in ( select * from emp where deptno=v_deptno )loop dbms_output.put_line(cur_emp.empno||' '||cur_emp.ename||' '||cur_emp.job||' '||cur_emp.sal); end loop; end if; exception when no_data_found then dbms_output.put_line('没有数据'); when too_many_rows then dbms_output.put_line('对应数据不唯一'); end testpro4;
练习:根据输入的部门编号和工资涨幅金额对部门下的员工工资信息调整,并返回修改的记录数。 create or replace procedure testpro6(p_deptno in number, p_num in out number) is begin update emp set sal=sal+p_num where deptno=p_deptno; if sql%found then p_num:=sql%rowcount; end if; end testpro6; 调用: declare v_num number; begin v_num:=300; testpro6(10,v_num); dbms_output.put_line(v_num); end;