游标的灵活运用

来源:互联网 发布:mysql保存特殊字符 编辑:程序博客网 时间:2024/05/17 03:57

游标概念:游标是一个指向上下文的句柄或指针,可以用来控制上下文区和处理语句时上下文区发生的事情。

 

 游标类型:游标的类型包括隐式游标、显式游标和REF游标。

隐式游标:在PL/SQL程序中执行DML SQL语句时自动创建隐式游标。

显示游标:用于处理返回多行的查询。

REF游标:用户处理运行是才能确定的动态SQL查询的结果。

一、隐式游标

PL/SQL中使用DML语句时自动创建隐式游标。隐式游标自动声明、打开和关闭,其名为SQL。通过检查隐式游标的属性可以获得最近执行的DML语句的信息。

隐式游标的属性有:

%FOUNDSQL语句影响了一行或多行时为true

%NOTFOUNDSQL语句没有影响任何行时为true

%ROWCOUNTSQL语句影响的行数

%ISOPEN:游标是否打开,始终未false

隐式游标实例1

SQL> declare

    v_RoomData rooms%ROWTYPE;

    begin

    select * into v_RoomData from rooms where room_id = -1;

    if SQL%NOTFOUND THEN 

    insert into temp_table(char_col) values('NO FOUNT!');

    end if;

    exception

    when NO_DATA_FOUND then

    insert into temp_table(char_col) values('Not found,exception handler');

    end;

    /

说明:注意,这里如果rooms表中没有room_id等于-1的行记录,会引发预定义异常exception

而不会去执行(if SQL%NOTFOUND THEN

隐式游标实例2

SQL> begin

    update toys set toyprice=270 where toyid=123;

    if SQL%FOUND then

    dbms_output.put_line('表已更新');

    end if;

    end;

    /

说明:对于修改语句,如果修改了记录,即影响了一行或者多行,这SQL%FOUND返回true

隐式游标实例3

SQL> declare

    v_toyid toys.toyid%type:='&toyid';

    v_toyname toys.name%type:='&toyname';

    begin

    update toys set name = v_toyname where toyid=v_toyid;

    if SQL%NOTFOUND then

    dbms_output.put_line('编号未找到。');

    else

    dbms_output.put_line('表已经更新');

    end if;

    end;

    /

隐式游标实例4:(NOTFOUND使用)

SQL> declare

  2  flag char:= 'U';

  3  begin

  4  update dept set dname='yingfeng' where deptno=50;

  5  if SQL%NOTFOUND then

  6  flag:='Z';

  7   insert into dept(deptno,dname) values(50,'yingfeng');

  8  end if;

  9  if flag='U' then

 10  dbms_output.put_line('update');

 11  else

 12  dbms_output.put_line('insert');

 13  end if;

 14  end;

 15  /

隐式游标实例5:(FOUND使用)

SQL> begin 

  2  update mark set marks=60 where cource='001' and marks<60;

  3  if SQL%FOUND then

  4  dbms_output.put_line('成绩已更新');

  5  end if;

  6  end;

  7  /

隐式游标实例6:(rowcount使用)

SQL> begin update emp set sal = sal+200 where sal<2000;

  2  Dbms_Output.put_line('update'||SQL%rowcount||'records');

  3  end;

  4  /

说明:返回受影响的行数

隐式游标实例6:(rowcount使用)

SQL> declare

  2  v_rows number;

  3  begin

  4  update emp set comm = 1000 where deptno=30;

  5  v_rows:=SQL%rowcount;

  6  dbms_output.put_line('update '|| v_rows ||' rows');

  7  end;

  8  /

说明:返回受影响的行数

隐式游标实例8:(促发异常,隐式游标不起作用)

SQL> declare

  2  empid varchar2(10);

  3  desig varchar2(10);

  4  begin

  5  empid:='&Employeeid';

  6  select designation into desig from employee where empno=empid;

  7  exception

  8  when NO_DATA_FOUND then

  9  dbms_output.put_line('not found data');

 10  end;

 11  /

说明:如果select into语句没有返回值,将促发NO_DATA_FOUND异常

隐式游标实例8:(促发异常,隐式游标不起作用)

SQL> declare

  2  empid varchar2(10);

  3  begin

  4  select empno into empid from empployee;

  5  exception

  6  when TOO_MANY_ROWS then

  7  dbms_output.put_line('too many rows');

  8  end;

  9  /

说明:如果select into语句返回多个值,将促发TOO_MANY_ROWS异常

隐式游标小结:

隐式游标由PL/SQL自动定义、打开和关闭

隐式游标的应用


二、显示游标

显示游标在PL/SQL块的声明部分定义查询,该查询可以返回多行。

显示游标的操作过程:首先数据库打开游标;然后提取行,把提取的行的数据放到变量中去;使用完之后最后要关闭游标。如果有多行需要用循环来控制。如图所示:

 

声明游标:cursor   is   select  

打开游标:open

结果集控制:fetch   into 

关闭游标:close

显示游标实例1:(打开显示游标)

SQL> declare

  2  my_toy_price toys.toyprice%type;

  3  cursor toy_cur is

  4  select toyprice from toys where toyprice<250;

  5  begin

  6  open toy_cur;

  7  loop

  8  fetch toy_cur into my_toy_price;

  9  exit when toy_cur%NOTFOUND;

 10  dbms_output.put_line('toyprice='||my_toy_price);

 11  end loop;

 12  close toy_cur;

 13  end;

 14  /

显示游标实例2:(打开显示游标)

SQL> declare

  2  cursor mycur is

  3  select * from dept order by deptno;

  4  myreco dept%rowtype;

  5  begin

  6  open mycur;

  7  fetch mycur into myreco;

  8  while mycur%found loop

  9  dbms_output.put_line(myreco.deptno || ' ' ||myreco.log);

 10  fetch mycur into myreco;

 11  end loop;

 12  close mycur;

 13  end;

 14  /

带参数的显示游标:

声明显示游标时可以带参数以提高灵活性

声明带参数的显示游标的语法如下:

Cursor<cursor_name>(<param_name><param_type>) is select_statement;

显示游标实例3:(带参数的显示游标)

SQL> declare

  2  desig varchar2(20);

  3  emp_code varchar2(5);

  4  empnm varchar2(20);

  5  cursor emp_cur(desigparam varchar2) is

  6  select empno,ename from employee where designation = desig;

  7  begin

  8  desig:='&desig';

  9  open emp_cur(desig);

 10  loop

 11  fetch emp_cur into emp_code,empnm;

 12  exit when emp_cur%NOTFOUND;

 13  dbms_output.put_line(emp_code||' '||empnm);

 14  end loop;

 15  close emp_cur;

 16  end;

 17  /

显示游标实例4:(带参数的显示游标)

SQL> declare

  2  cursor mycur(my_job varchar2) is

  3  select * from emp where job=my_job;

  4  begin

  5  for myreco in mycur('SALESMAN') loop

  6  dbms_output.put_line(myreco.ename);

  7  end loop;

  8  end;

  9  /

显示游标实例5:(带参数的显示游标)

SQL> declare

  2  dept_no emp.deptno%type;

  3  emp_no emp.empno%type;

  4  emp_name emp.ename%type;

  5  cursor emp_cur(deptparam number) is 

  6  select empno,ename from emp where deptno=deptparam;

  7  begin

  8  dept_no:=&deptno;

  9  open emp_cur(dept_no);

 10  loop

 11  fetch emp_cur into emp_no,emp_name;

 12  dbms_output.put_line(emp_no||' '||emp_name);

 13  exit when emp_cur%NOTFOUND;

 14  end loop;

 15  close emp_cur;

 16  end;

 17  /

使用显示游标更新行

运行使用游标删除或更新活动集中的行

声明游标时必须使用select...for update 语句

语法如下:

Cursor<cursor_name> is select statement for update;

更新的语法:

Update<table_name> set<set_clause> where current of<cursor_name>

删除的语法:

Delete from<table_name> where current of<cursor_name>

显示游标实例6:(使用显示游标更新行)

SQL> declare

  2  new_price number;

  3  cursor cur_toy is

  4  select toyprice from toys where toyprice<100

  5  for update of toyprice;

  6  begin

  7  open cur_toy;

  8  loop

  9  fetch cur_toy into new_price;

 10  exit when cur_toy%NOTFOUND;

 11  update toys

 12  set toyprice=10*new_price

 13  where current of cur_toy;

 14  end loop;

 15  close cur_toy;

 16  commit;

 17  end;

 18  /

显示游标实例7:(使用显示游标删除行)

SQL> declare

  2  cursor mycur(dept_no integer) is

  3  select * from dept where deptno>dept_no for update;

  4  begin

  5  for myreco in mycur(50) loop

  6  delete from dept where current of mycur;

  7  end loop;

  8  end;

  9  /

循环游标

循环游标用于简化游标处理代码

当用户需要从游标中提取所有记录时使用

循环游标的语法如下:

for<record_index> in <cursor_name> 

Loop

<executable statements>

End loop;

显示游标实例8:(循环游标)

SQL> declare

  2  cursor mytoy_cur is 

  3  select toyid,name,toyprice from toys;

  4  begin

  5  for toy_rec in mytoy_cur

  6  loop

  7  dbms_output.put_line(toy_rec.toyid||' '||toy_rec.name||' '||toy_rec.toyprice);

  8  end loop;

  9  end;

 10  /

显示游标实例9:(循环游标)

SQL> declare

  2  cursor c_dept is

  3  select deptno,dname from dept order by deptno;

  4  cursor c_emp(p_dept varchar2) is

  5  select ename,sal from emp where deptno=p_dept order by ename;

  6  v_salary emp.sal%type;

  7  begin

  8  for r_dept in c_dept loop

  9  dbms_output.put_line('Department:'||r_dept.deptno||'-'||r_dept.dname);

 10  v_salary:=0;

 11  for r_emp in c_emp(r_dept.deptno)loop

 12  dbms_output.put_line('Name:'||r_emp.ename||' salary='||r_emp.sal);

 13  v_salary:=v_salary+r_emp.sal;

 14  end loop;

 15  dbms_output.put_line('Total salary for dept:'||v_salary);

 16  end loop;

 17  end;

 18  /

三、REF游标和游标变量

REF游标和游标变量用于处理运行是动态执行的SQL查询

创建游标变量需要两个步骤:

1、声明REF游标类型

2、声明REF游标类型的变量

用于声明REF游标类型的语法为:

Type<ref_cursor_name> is ref cursor [return <return_type>];

打开游标变量的语法如下:

Open cursor_name for select_statement;

声明强类型的REF游标(指定返回值类型)

Type my_curtype is ref cursor

Return stud_det%ROWTYPE;

Order_cur my_curtype;

声明弱类型的REF游标(没有指定返回类型)

Type my_ctype is ref cursor;

Stud_cur my_ctype;

Ref游标实例1:(弱类型ref实现)

SQL> declare

  2  type cursor_type is ref cursor;

  3  stu_cursor cursor_type;

  4  v_stu student%rowtype;

  5  begin

  6  open stu_cursor for

  7  select * from student where sex = 'M';

  8  loop

  9  fetch stu_cursor into v_stu;

 10  

 10  exit when stu_cursor%notfound;

 11  dbms_output.put_line(v_stu.studentid||' '||v_stu.name||' '||v_stu.sex||' '||v_stu.age);

 12  end loop;

 13  close stu_cursor;

 14  end;

 15  /

游标变量的优点和限制

游标变量的功能强大,可以简化数据处理。

游标变量的优点有:

1、可以从不同的select语句中提取结果集

2、可以作为过程的参数进行传递

3、可以引用游标的所有属性

4、可以进行赋值运算

使用游标变量的限制:

1、不能在程序包中声明游标变量

2、For update自己不能与游标变量一起使用

3、不能使用比较运算符

使用游标变量执行动态SQL

可以使用游标变量执行动态构造的SQL语句

打开执行动态SQL的游标变量的语法如下:

Open cursor_name for dynamic_sqlstring [using bing_argument_list]

Ref游标实例2:(使用游标变量执行动态sql

SQL> declare 

  2  r_emp emp%rowtype;

  3  type c_type is ref cursor;

  4  cur c_type;

  5  p_salary number;

  6  begin

  7  p_salary:=2500;

  8  open cur for 'select * from emp where sal>:1 order by sal desc' using p_salary;

  9  dbms_output.put_line('薪水大于'||p_salary||'的员工有:');

 10  loop

 11  fetch cur into r_emp;

 12  exit when cur%notfound;

 13  dbms_output.put_line('编号:'||r_emp.empno||' 姓名:'||r_emp.ename||' 薪水:'||r_emp.sal);

 14  end loop;

 15  close cur;

 16  end;

 17  /

说明:>:1表示吧using后面的p_salary的值赋值进去sql语句中。如果有多个变量,可以用1234分别代替,using后面变量之间用“,”隔开。

Ref游标实例3:(使用游标变量执行动态sql

SQL> declare

  2  type emp_type is ref cursor;

  3  cur emp_type;

  4  name varchar2(20);

  5  salary number(7,2);

  6  begin

  7  open cur for 'select ename,sal from emp where job=:1'

  8  using 'SALESMAN';

  9  loop

 10  fetch cur into name,salary;

 11  exit when cur%notfound;

 12  dbms_output.put_line(name||':'||salary);

 13  end loop;

 14  close cur;

 15  end;

 16  /

使用bulk

使用bulk批量提取游标,可以加快我们提取数据的速度,可以不需要用循环来一行行地提取。提高插入、更新和删除的效率。

Ref游标实例4:(bulk批量提取的使用

SQL> declare

  2  type empcurtyp is ref cursor;

  3  type idlist is table of emp.empno%type;

  4  type namelist is table of emp.ename%type;

  5  type sallist is table of emp.sal%type;

  6  emp_cv empcurtyp;

  7  ids idlist;

  8  names namelist;

  9  sals sallist;

 10  row_cn number;

 11  begin

 12  open emp_cv for select empno,ename,sal from emp;

 13  fetch emp_cv bulk collect into ids,names,sals;

 14  close emp_cv;

 15  for i in ids.first..ids.last loop

 16  dbms_output.put_line(ids(i)||' '||names(i)||' '||sals(i));

 17  end loop;

 18  end;

 19  /

CursorRef Cursor区别

从技术底层看,两者是相同的。普通plsql cursor在定义时是“静态”的。而Ref cursors可以动态打开。

1、Ref cursor根据逻辑动态打开;而游标cursor定义好了就无法修改了

2、Ref cursor可以返回给客户端,cursor则不行

3、Cursor可以是全局的globalref cursor则必须定在过程或函数中

4、Ref cursor可以在子程序间传递,cursor则不行。

5、Cursor中定义的静态sqlref cursor效率高,所以ref cursor通常用在:向客户端返回结果集。

游标总结:

1、游标用于处理查询结果集中的数据

2、游标类型有:隐式游标、显示游标和REF游标

3、隐式游标由PL/SQL自动定义、打开和关闭

4、显示游标用于处理返回多行的查询

5、显示游标可以删除和更新活动集中的行

6、要处理结果集中所有的记录时,可使用循环游标

7、在声明REF游标时,不需要将select语句与其他关联。


0 0