1.基础定义

游标本质上就是一块内存区域,由系统或用户以变量的形式定义,可以提高数据数据处理的效率。

2.工作机制

将查询出的多条记录统一放入内存中,游标再从内存中拿取数据

3.解决问题

可以解决一次性查询多条记录的问题,处理多行数据的事务经常使用游标来实现

4.游标属性
游标名%isopen:判断游标是否打开,值是布尔类型,默认为false
游标名%found:判断游标是否找到记录,默认为false,找到记录为true
游标名%notfound:判断游标是否找到记录,默认为false,没找到为true
游标名%rowcount:获取游标影响的记录数,默认值为0,若将查询到的数据放入内存中,但游标并没有从内存中取数据,此时值为0

5.分类

隐式游标:使用DML语句时会自动创建,自动声明,打开及关闭,名称为SQL,检查属性获取最近执行信息,隐式游标是无法进行操作的。

显示游标:手动创建,开启,关闭,从内存中提取数据

ref游标:动态游标,定义时不需要指定select语句,使用时需要指定select语句

6.隐式游标

创建一个类型转换函数

create or replace function bool2char(bool boolean) return varchar2 is
begin
  if bool then
    return 'TRUE';
  else
    return 'FALSE';
  end if;
end;

布尔类型的值是无法直接被打印的,所以需要先转换类型

DECLARE
V_EMP EMP%ROWTYPE;
BEGIN
  SELECT * INTO V_EMP FROM EMP WHERE ROWNUM<2;
  DBMS_OUTPUT.PUT_LINE(bool2char(SQL%ISOPEN));
  DBMS_OUTPUT.PUT_LINE(bool2char(SQL%FOUND));
  DBMS_OUTPUT.PUT_LINE(bool2char(SQL%NOTFOUND));
  DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT);
END;

7.显示游标

声明游标:cursor 游标名 is select语句;

打开游标:open 游标名;

提取数据:fetch 游标名 into 变量;

关闭游标:close 游标名;

当提取到最后一条数据时,再次进行提取返回的结果仍然是最后一条数据,并不会以null值进行覆盖。

DECLARE
CURSOR CUR IS SELECT * FROM EMP WHERE ROWNUM<3;
V_EMP EMP%ROWTYPE;
BEGIN
  OPEN CUR;
  FETCH CUR INTO V_EMP;
  DBMS_OUTPUT.PUT_LINE(V_EMP.ENAME);
  FETCH CUR INTO V_EMP;
  DBMS_OUTPUT.PUT_LINE(V_EMP.ENAME);
  FETCH CUR INTO V_EMP;
  DBMS_OUTPUT.PUT_LINE(V_EMP.ENAME);
  CLOSE CUR;
END;

8.属性应用

python 判断游标是否关闭_sql

DECLARE
  CURSOR CUR IS SELECT * FROM EMP WHERE ROWNUM<3;
  V_EMP EMP%ROWTYPE;
  BEGIN
    --在open(打开游标)之前
    DBMS_OUTPUT.PUT_LINE(bool2char(CUR%ISOPEN));--FALSE
    --DBMS_OUTPUT.PUT_LINE(bool2char(CUR%FOUND));--错误
    --DBMS_OUTPUT.PUT_LINE(bool2char(CUR%NOTFOUND));--错误
    --DBMS_OUTPUT.PUT_LINE(CUR%ROWCOUNT);--错误
    OPEN CUR;
    --打开游标之后
    DBMS_OUTPUT.PUT_LINE(bool2char(CUR%ISOPEN));--true
    DBMS_OUTPUT.PUT_LINE(bool2char(CUR%FOUND));--false,只是将游标打开而并没有对数据进行提取
    DBMS_OUTPUT.PUT_LINE(bool2char(CUR%NOTFOUND));--FALSE
    DBMS_OUTPUT.PUT_LINE(CUR%ROWCOUNT);--0
    FETCH CUR INTO V_EMP;
    --提取数据之后
    DBMS_OUTPUT.PUT_LINE(bool2char(CUR%FOUND));--TRUE
    DBMS_OUTPUT.PUT_LINE(bool2char(CUR%NOTFOUND));--FALSE
    DBMS_OUTPUT.PUT_LINE(CUR%ROWCOUNT);--1
    CLOSE CUR;
    --关闭游标之后
    DBMS_OUTPUT.PUT_LINE(bool2char(CUR%ISOPEN));--FALSE,游标已经关闭
    --DBMS_OUTPUT.PUT_LINE(bool2char(CUR%FOUND));--错误
    --DBMS_OUTPUT.PUT_LINE(bool2char(CUR%NOTFOUND));--错误
    --DBMS_OUTPUT.PUT_LINE(CUR%ROWCOUNT);--错误
  END;

9.游标原理

(1)定义游标时会分配一块内存区域,内存中并没有任何数据。
(2)打开内存,将结果集存入内存。
(3)打开游标后,内存中的指针会指向第一条数据。
(4)提取数据时,会提取指针指向的数据,此时指针会指向下一条数据,当提取玩最后一条数据时指针会指向并不存在任何数据的位置,当再次提取数据时found值会变为false,notfound值变为true。
(5)关闭游标是为了释放内存资源。

 10.显式游标的应用

(1)循环遍历游标

--loop循环遍历游标

DECLARE
    CURSOR CUR IS SELECT * FROM EMP  ;
    V_EMP EMP%ROWTYPE;
    BEGIN
      OPEN CUR;
      LOOP
        FETCH CUR INTO V_EMP;
        EXIT WHEN CUR%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(V_EMP.ENAME);
      END LOOP;
      CLOSE CUR;
    END;

--while循环遍历游标

DECLARE
    CURSOR CUR IS SELECT * FROM EMP ;
    V_EMP EMP%ROWTYPE;
    BEGIN
      OPEN CUR;
      FETCH CUR INTO V_EMP;
      WHILE CUR%FOUND LOOP
        DBMS_OUTPUT.PUT_LINE(V_EMP.ENAME);
        FETCH CUR INTO V_EMP;
      END LOOP;
      CLOSE CUR;
    END;

 在while循环开始之前就开始提取数据是为了让found生效,found的含义是找到数据为true,若没有提取数据,则while循环的表达式就一直为false,是进不去循环的。

--for循环遍历游标,进入for循环时会自动打开游标并自动提取数据,退出for循环时会自动关闭游标,所以并没有必要使用open,fetch,close取对游标进行操作。

DECLARE
    CURSOR CUR IS SELECT * FROM EMP ;
    BEGIN
      FOR V_EMP IN CUR LOOP
        DBMS_OUTPUT.PUT_LINE(V_EMP.ENAME);
      END LOOP;
    END;

(2)引用游标类型

declare
cursor cur is select * from emp;
v_emp cur%rowtype;
begin
  open cur;
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('编号:'||v_emp.empno||'姓名:'||v_emp.ename);    
  end loop;
  close cur;
end;

(3)into多个变量

declare
cursor cur is select empno,ename from emp;
v_empno emp.empno%type;
v_ename emp.ename%type;
begin
  open cur;
  loop
    fetch cur into v_empno,v_ename;
    exit when cur%notfound;
    dbms_output.put_line('编号:'||v_empno||'姓名:'||v_ename);    
  end loop;
  close cur;
end;

(4)记录类型

declare
cursor cur is select empno,ename from emp;
type t_type is record(v_empno number(4),v_ename varchar2(10));
v_emp t_type;
begin
  open cur;
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('编号:'||v_emp.v_empno||'姓名:'||v_emp.v_ename);    
  end loop;
  close cur;
end;

(5)游标带返回值

declare
cursor cur return emp%rowtype is select * from emp;
begin
  for v_emp in cur loop
    dbms_output.put_line('编号:'||v_emp.empno||'姓名:'||v_emp.ename); 
  end loop;
end;

(6)游标带参数(传参)

declare
cursor cur(v_deptno number) is select * from emp where deptno=v_deptno;
v_emp cur%rowtype;
begin
  open cur(&部门编号);
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('编号:'||v_emp.empno||'姓名:'||v_emp.ename);
  end loop;
  close cur;
end;

(7)可更新游标,select语句后加上for update,where current of 游标名,根据指针更新数据

declare
cursor cur is select * from emp for update;
begin
  for v_emp in cur loop
    if v_emp.comm is null then
      update emp set comm=100 where current of cur;
    end if;
  end loop;
end;

11.ref游标

语法:
declare
--声明游标类型
type t_cur is ref cursor;

--声明游标
cur t_cur;
v_emp emp%rowtype;
begin
  --打开游标
  open cur for 'select 语句';--for后的select语句也可以不加单引号
  --提取数据
  fetch cur into v_emp;
  dbms_output.put_line(v_emp.ename);
  --关闭游标
  close cur;
end;

12.ref游标应用

ref游标分为强类型和弱类型,强类型是有返回值的,二弱类型是没有返回值的

(1)游标没有返回值(弱类型)

这是错误的,游标在声明时没有指定具体的数据类型,v_emp引用游标类型。

declare
type t_cur is ref cursor;
cur t_cur;
v_emp emp%rowtype;
begin
  open cur for select * from emp;
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('姓名:'||v_emp.ename);
  end loop;
  close cur;
end;
declare
type t_cur is ref cursor;
cur t_cur;
v_emp cur%rowtype;
begin
  open cur for select * from emp;
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('姓名:'||v_emp.ename);
  end loop;
  close cur;
end;

python 判断游标是否关闭_数据库_02

python 判断游标是否关闭_sql_03

 (2)游标带返回类型(强类型)

declare
type t_cur is ref cursor return emp%rowtype;
cur t_cur;
v_emp cur%rowtype;
begin
  open cur for select * from emp;
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('姓名:'||v_emp.ename);
  end loop;
  close cur;
end;

ref游标为强类型,打开游标时不能将sql以字符串的形式存在。

declare
type t_cur is ref cursor return emp%rowtype;
cur t_cur;
v_emp cur%rowtype;
begin
  open cur for 'select * from emp';
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('姓名:'||v_emp.ename);
  end loop;
  close cur;
end;

python 判断游标是否关闭_SQL_04

(3)sql字符串提取出来

declare
type t_cur is ref cursor;
cur t_cur;
v_emp emp%rowtype;
v_sql varchar2(100):='select * from emp';
begin
  v_sql:=v_sql||' where deptno=10';
  dbms_output.put_line(v_sql);
  open cur for v_sql;
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('姓名:'||v_emp.ename);
  end loop;
  close cur;
end;

(4)using占位符

declare
type t_cur is ref cursor;
cur t_cur;
v_emp emp%rowtype;
v_sql varchar2(100):='select * from emp where deptno=:1';
begin
  open cur for v_sql using &部门号;
  loop
    fetch cur into v_emp;
    exit when cur%notfound;
    dbms_output.put_line('姓名:'||v_emp.ename);
  end loop;
  close cur;
end;

(5)其他循环遍历

while循环

declare
type t_cur is ref cursor;
cur t_cur;
v_emp emp%rowtype;
begin
  open cur for select * from emp;
  fetch cur into v_emp;
  while cur%found loop
    dbms_output.put_line('姓名:'||v_emp.ename);
    fetch cur into v_emp;
  end loop;
  close cur;
end;

for循环:不能用于ref游标

declare
type t_cur is ref cursor;
cur t_cur;
begin
  for v_emp in cur loop
    dbms_output.put_line('姓名:'||v_emp.ename);
  end loop;
end;

python 判断游标是否关闭_SQL_05

(6)ref游标传参:不能带参数

declare
type t_cur is ref cursor;
cur t_cur;
v_emp emp%rowtype;
begin
  open cur(10) for select * from emp where deptno=v_deptno;
  fetch cur into v_emp;
  dbms_output.put_line('姓名:'||v_emp.ename);
  close cur;
end;

python 判断游标是否关闭_SQL_06