游标就是一个指向内存的指针 1.隐式游标 ----意义在于对DML语句返回值的监控 pl/sql 中【DML】操作的时候自动创建隐式游标 通过检查隐身游标的属性可以获得【最近】执行的DML的信息 %found ----语句影响了一行或者多行是为true %notfound ---sql没有影响任何行时为true %rowcount ---sql语句影响的行数 %isopen --游标是否打开,始终为false 使用的时候一般SQL%found 等等 注意:隐式游标与select无关,只适用于DML 如果是select查不到东西,将发生NO_DATA_FOUND异常 SELECT * INTO v_RoomData FROM rooms WHERE room_id = -1; EXCEPTION WHEN NO_DATA_FOUND THEN/*注意,这是真正执行的*/ INSERT INTO temp_table (char_col) VALUES ('Not found, exception handler'); 如果select 返回太多,抛TOO_MANY_ROWS异常 BEGIN SELECT empno INTO empid FROM employee; EXCEPTION WHEN TOO_MANY_ROWS THEN DBMS_OUTPUT.PUT_LINE('该查询提取多行'); END 2.显示游标----意义在于对select语句的多行记录进行保存 2.1 声明游标:CURSOR ..IS select.. 打开游标:OPEN 结果集控制:FETCH..INTO.. 关闭游标:CLOSE cursor v_cursor is select * from xxx; ---创建游标实例,并把数据放入 open v_cursor; loop fetch v_cursor into v_table; exit when v_cursor%notfound; dbms_output.put_line(v_table.name); ... end loop; close v_cursor; 2.2 带参数的显示游标 cursor v_cursor(param_id number) is select * from xxx where id= param_id; open v_cursor(5); 后面是一样的,就相当于使用了绑定变量 2.3 使用游标查出东西来,然后再更改游标中的行,最后一次性插入数据库 cursor v_cursor is select * from emp for update of salary; --全部都想更新,那么for update就ok了 begin open v_cursor; loop fetch v_cursor into emp_temp; exit when emp_temp%notfound; update emp ---还可以删除,但是上面申明时候出现的关键字update不变 set salary=1.1*emp_temp.salary where current of v_cursor; --这里指定修改的是游标中的当前条记录 end loop; close v_cursor; commit; end; 3.ref游标-----意义在于声明游标时不绑定select语句,而是在打开的时候绑定 这种一般用于out参数,传出去的 type UserInfo_cursor is ref cursor; 或者: type UserInfo_cursor is ref cursor return emp%rowtype; ----相当于定义泛型,oracle叫他强类型 open parm_UserInfo for select * from xxx; 因为是要传出去,所以不用关闭 cursor显示和ref cursor的区别: Ref cursor根据逻辑动态打开;而游标cursor定义好了就无法修改了 ref cursor可以返回给客户端,cursor则不行。----这个是重点 cursor可以是全局的global ,ref cursor则必须定义在过程或函数中。 ref cursor可以在子程序间传递,cursor则不行。 cursor中定义的静态sql比ref cursor效率高,所以ref cursor通常 用在:向客户端返回结果集。 小知识:循环游标语法----意义在于简化游标处理代码,当用户需要从游标中提取所有记录时使用 这个不是一种游标,而是一种提取游标的方法,他不需要打开和关闭游标 声明相同 begin for a in v_cursor ---相当于java中增强for loop ...... end loop; end; -------------------------- 小例子--------------------------------------------------------------------------------- SQL> create or replace package pkg_SelectUserInfo --根据用户类型查看用户信息 2 as 3 type UserInfo_cursor is ref cursor; 4 procedure GetUserInfo_proc 5 (parm_RoleName in varchar2, 6 parm_UserInfo out UserInfo_cursor); 7 end pkg_SelectUserInfo; 8 / 程序包已创建。 SQL> create or replace package body pkg_SelectUserInfo 2 as 3 procedure GetUserInfo_proc 4 (parm_RoleName in varchar2, 5 parm_UserInfo out UserInfo_cursor) 6 is 7 begin 8 open parm_UserInfo for 9 select UserID,UserName,PassWord,RoleName 10 from UserInfo,RoleInfo 11 where UserInfo.UserRole=RoleInfo.RoleID and 12 RoleName like parm_RoleName; 13 end; 14 end pkg_SelectUserInfo; 15 / 或者: SQL> create or replace package body pkg_SelectUserInfo 2 as 3 procedure GetUserInfo_proc 4 (parm_RoleName in varchar2, 5 parm_UserInfo out UserInfo_cursor) 6 is sqlstr varchar2(500); 7 begin sqlstr:='select UserID,UserName,PassWord,RoleName 10 from UserInfo,RoleInfo 11 where UserInfo.UserRole=RoleInfo.RoleID and 12 RoleName like :v_role_name'; 8 open parm_UserInfo for sqlstr using parm_RoleName ; 13 end; 14 end pkg_SelectUserInfo; 15 / ------------------------------------ 传入的str= 1111,2222,34444,sdfef,213213,sfsd 要分割打印: 思路:以逗号为参照系,当前逗号位置 --- 前一个逗号位置 = 长度 + 1 create or replace procedure get_user_id (user_str varchar2) as result varchar2(50); seq number; current_idx number ; pre_idx number ; user_str2 varchar2(50); begin user_str2 := ','||user_str||','; seq :=2; current_idx := instr(user_str2,',',1,seq); pre_idx:=1; while current_idx!=0 loop result := substr(user_str2,pre_idx+1,current_idx-1-pre_idx); dbms_output.put_line(result); pre_idx := current_idx; seq := seq+1; current_idx := instr(user_str2,',',1,seq); end loop; end; / ------------过程的输出参数还可以这样用----------- create or replace procedure newsidproc --通过公告标题、内容、发布时间获取公告id (parm_title in varchar2, parm_content in varchar2, parm_newstime in date, parm_newsid out number ) as begin select newsid into parm_newsid from news where title=parm_title and content=parm_content and newstime=parm_newstime; end create or replace procedure updatenews --修改公告 ( parm_title varchar2, parm_content varchar2, parm_newstime in date ) as v_newsid; begin v_newsid:=newsidproc(parm_title,parm_content ,parm_newstime) update news set title=parm_title, content=parm_content where newsid=parm_newid; commit; end;