数据库之【游标使用详解篇】

*****************************

数据库之游标使用详解篇

*****************************

游标(Cursor):用来查询数据库,获取记录集合(结果集)的指针,可以让开发者一次访问一行结果集,

                                在每条结果集上作操作。
游标类型:隐式游标,显示游标,REF游标。
                 其中,隐式游标和显示游标属于静态游标(运行前将游标与SQL语句关联),
                 REF游标属于动态游标(运行时将游标与SQL语句关联)。
隐式游标:DML语句对应的游标,由Oracle自动管理,也称SQL游标。

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

游标变量的优点有:
1.可从不同的 SELECT 语句中提取结果集
2.可以作为过程的参数进行传递
3.可以引用游标的所有属性
4.可以进行赋值运算

使用游标变量的限制:
1.不能在程序包中声明游标变量
2.FOR UPDATE子句不能与游标变量一起使用
3.不能使用比较运算符

显式和隐式游标的区别:
尽量使用隐式游标,避免编写附加的游标控制代码(声明,打开,获取,关闭),

也不需要声明变量来保存从游标中获取的数据。


--1.静态游标(隐式游标和显示游标)
--1.1隐式游标
--隐式游标的属性
%FOUND    --有记录为真
%NOTFOUND --没记录时为真
%ROWCOUNT --引响到表里记录的行数
%ISOPEN   --游标的状态(OPEN,CLOSE)
SQL       --所有隐式游标的名称
--隐式游标属性%FOUND的用法
BEGIN
  UPDATE emp SET sal = 2000 WHERE empno = '7369';
  IF SQL%FOUND THEN
    --SQL%NOTFOUND
    DBMS_OUTPUT.PUT_LINE('表已更新');
  END IF;
END;
/

--未找到数据异常NO_DATA_FOUND
DECLARE
  empid VARCHAR2(10);
  desig VARCHAR2(10);
BEGIN
  empid := '&Employeeid';
  SELECT ename INTO desig FROM emp WHERE empno = empid;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('职员未找到');
END;
--隐式游标属性SQL%ROWCOUNT用法
BEGIN
  UPDATE vendor_master SET venname = 'Rob Mathew' WHERE vencode = 'V004';
  DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
END;
/
--select into 时错误TOO_MANY_ROWS
DECLARE
  empid VARCHAR2(10);
BEGIN
  SELECT empno INTO empid FROM emp;
EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('该查询提取多行');
END;
/

--1.2.显示游标
显示游标操作:
(1)声明游标(关联SQL语句) cursor+游标名 is/as sql语句
(2)打开游标(执行SQL语句,填充游标) open+游标名
(3)提取游标的行 fetch 游标名 into 行类型变量
(4)关闭游标 close+游标名

declare
  --定义存储游标变量
  rowresult emp%rowtype;
  --定义游标
  cursor cur is
    select * from emp where sal > 2000;
begin
  open cur; --打开
  loop      --循环
    fetch cur
      into rowresult;       --提取
    exit when cur%notfound; --退出
    dbms_output.put_line('员工姓名:' || rowresult.ename); --从游标变量中取某个字段值
  end loop;
  close cur; --关闭
end;

--带参数的显示游标
declare
  rowresult emp%rowtype;
  cursor cur(eno number) is
    select * from emp where empno = eno;
begin
  open cur(&empno);
  loop
    fetch cur
      into rowresult;
    exit when cur%notfound;
    dbms_output.put_line('用户名是:' || rowresult.ename);
  end loop;
  close cur;
end;

--使用显示游标更新记录
declare
  new_sal number;
  cursor cur is
    select sal from emp where sal < 3000 for update of sal;
begin
  open cur;
  loop
    fetch cur
      into new_sal;
    exit when cur%notfound;
    update emp set sal = 1.1 * new_sal where current of cur;
    dbms_output.put_line('记录已经更新' || 1.1 * new_sal);
  end loop;
  close cur;
end;

--循环游标
declare
  cursor cur is
    select ename, sal from emp;
begin
  for new_cur in cur loop
    dbms_output.put_line('员工:' || new_cur.ename || '的工资是:' || new_cur.sal);
  end loop;
end;

--2.动态游标(Ref游标)
--2.1REF游标
accept tab prompt '你想查看什么信息? 员工信息(E)或部门信息(D):';--使用对话框输入参数
declare
  --定义引用游标类型
  type cur is ref cursor; --声明游标类型
  /*如果不指定返回类型为弱类型游标,如果指定了返回类型则为强类型,如下所示:*/
  --return emp%rowtype;
  --根据定义的引用游标类型声明游标变量
  new_cur   cur;
  p_id      number;
  p_name    varchar2(200);
  selection varchar2(1) := upper(substr('&tab', 1, 1)); --接收对话框输入参数
begin
  if selection = 'E' then
    open new_cur for
      select empno id, ename name from emp;
    dbms_output.put_line('=====员工信息表=====');
  elsif selection = 'D' then
    open new_cur for
      select deptno id, dname name from dept;
    dbms_output.put_line('=====部门信息表=====');
  else
    dbms_output.put_line('请输入员工信息(E)或部门信息(D)');
    return;
  end if;
  /*fetch new_cur into p_id,p_name;
  while new_cur%found loop
  dbms_output.put_line('#'||p_id||':'||p_name);
  fetch new_cur into p_id,p_name;
  end loop;*/ --递归提取游标数据方法
  loop
    --循环提取游标数据方法
    fetch new_cur
      into p_id, p_name;
    exit when new_cur%notfound;
    dbms_output.put_line('#' || p_id || ':' || p_name);
  end loop;
  close new_cur;
end;

--使用公用变量的动态查询语句
set serveroutput on;
variable aa number; --定义公用变量
execute :empno :=7369;--公用变量赋值

declare
  sqlstr  varchar2(2000);
  emp_row emp%rowtype;
  emno    number;
begin
  emno   := :empno; --使用公用变量
  sqlstr := 'select * from emp where empno=:id';
  --执行动态SQL
  execute immediate sqlstr
    into emp_row
    using emno;
  dbms_output.put_line('编号为:' || emno || '的工资为:' || emp_row.sal);
end;

--使用游标变量执行动态SQL
variable maxsal number;--在ORACLE中定义公用变量
execute :maxsal := 2500;--对公用变量赋值
declare
  r_emp   emp%rowtype;
  type    c_type is ref cursor;
  cur     c_type;
  p_salary number;
begin
  p_salary := :maxsal;
  open cur for 'select * from emp where sal >:1 order by sal desc'
    using p_salary; --引用公用变量,对WHERE条件的:1参数赋值
  dbms_output.put_line('薪水大于' || p_salary || '的员工有:');
  loop
    fetch cur
      into r_emp;
    exit when cur%notfound;
    dbms_output.put_line(':编号:' || r_emp.empno || '姓名' || r_emp.ename ||
                         '薪水:' || r_emp.sal);
  end loop;
  close cur;
end;





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章