游标的使用

游标


1、技术目标

  • 游标的使用


2、什么是游标?

游标是查询数据时指向结果集的指针,通过游标可一次访问结果集中
的一行,Oracle有两种游标:

  • 静态游标 ,在编译时知道select语句的游标,静态游标有两种:

    • 隐式游标
    • 显示游标

  • REF游标 ,有时候为游标使用的查询直到代码运行时才确定,
            这种情况使用REF游标(引用游标)和游标变量来实现,
            有两种REF游标:


    • 强类型REF游标
    • 弱类型REF游标


3、隐式游标

PL/SQL为DML语句隐式声明游标,用户不能命名和控制这种游标,所以
称为隐式游标,隐式游标使用属性返回信息,属性 包括:

  • %FOUND ,在DML语句影响一行或多行时返回true
  • %NOTFOUND ,没有影响任何行时返回true
  • %ROWCOUNT ,返回DML语句影响行数,如DML没有影响任何行返回0
  • %ISOPEN ,返回游标是否已打开的值,在SQL语句执行完后,Oracle自动关闭SQL游标,隐式游标的%ISOPEN属性始终为false


注意:通过检查隐式游标的属性可以获取与最近执行时的SQL语句相关的信息

使用1: 用%FOUND属性判断是否获取查询结果,

Sql代码 复制代码  收藏代码
  1. set serveroutput on  
  2. begin  
  3.     --查询   
  4.     update toys set toyprice=270 where toyid='T005';   
  5.     --判断是否有查询结果   
  6.     if SQL%FOUND then  
  7.         DBMS_OUTPUT.PUT_LINE('表已更新');   
  8.     else  
  9.         DBMS_OUTPUT.PUT_LINE('编号未找到');   
  10.     end if;   
  11. end;   
  12. /  
set serveroutput on
begin
    --查询
    update toys set toyprice=270 where toyid='T005';
    --判断是否有查询结果
    if SQL%FOUND then
        DBMS_OUTPUT.PUT_LINE('表已更新');
    else
        DBMS_OUTPUT.PUT_LINE('编号未找到');
    end if;
end;
/

 


使用2: 用%ROWCOUNT获取SQL语句执行所影响的行数,

Sql代码 复制代码  收藏代码
  1. set serveroutput on  
  2. begin  
  3.     update vendor_master set venname='Rob Mathew' where vencode='V004'  
  4.     DBMS_OUTPUT.PUT_LINE('更新了' || SQL%ROWCOUNT || '行');   
  5. end;   
  6. /  
set serveroutput on
begin
    update vendor_master set venname='Rob Mathew' where vencode='V004'
    DBMS_OUTPUT.PUT_LINE('更新了' || SQL%ROWCOUNT || '行');
end;
/

 


使用3 :按编号查询员工,判断是否查到,

Sql代码 复制代码  收藏代码
  1. set serveroutput on  
  2. declare  
  3.     empid varchar2(10);   
  4.     desig varchar2(20);   
  5. begin  
  6.     empid := '&职员编号';   
  7.     --根据员工编号查询出员工职位并给变量desig赋值   
  8.     select designation into desig from employee where empno = empid;   
  9.     if SQL%ROWCOUNT > 0 then  
  10.         DBMS_OUTPUT.PUT_LINE('职员的头衔是:' + desig);   
  11.     end if;   
  12.     exception   
  13.         when NO_DATA_FOUND then  
  14.             DBMS_OUTPUT.PUT_LINE('职员未找到');   
  15. end;   
  16. /  
set serveroutput on
declare
    empid varchar2(10);
    desig varchar2(20);
begin
    empid := '&职员编号';
    --根据员工编号查询出员工职位并给变量desig赋值
    select designation into desig from employee where empno = empid;
    if SQL%ROWCOUNT > 0 then
        DBMS_OUTPUT.PUT_LINE('职员的头衔是:' + desig);
    end if;
    exception
        when NO_DATA_FOUND then
            DBMS_OUTPUT.PUT_LINE('职员未找到');
end;
/

 


4、显示游标

显示游标是用户显示声明的游标,游标将指向活动集(查询结果)中的当前行,
使用显示游标的
步骤:

   
1)声明
    2)打开
    3)从游标中获取记录
    4)关闭游标


显示游标在PL/SQL程序的DECLARE部分声明,语法 为:

CURSOR cursor_name [(parameter [, parameter] ...)]
[return return_type]
IS
select_statement;

语法说明:

cursor_name:游标名称
parameter:指定输入参数
return type:定义游标提取的行的类型
select_statement:游标定义的查询语句

游标声明后,可使用如下语句控制游标

  • open :打开游标,open cursor_name [ (parameters) ];
  • fetch :从游标中提取行,fetch cursor_name into variables;
    写在循环内,用于从结果集中一次检索一行,
    每次提取后指针就向前移动一行
  • close :关闭游标,close cursor_name,游标处理完后必须关闭


使用1: 声明游标toy_cur,打开并使用该游标提取所有行,

Sql代码 复制代码  收藏代码
  1. set serveroutput on  
  2. declare  
  3.     --定义变量my_toy_price,其类型与toyprice字段一致   
  4.     my_toy_price toys.toyprice%TYPE;   
  5.     CURSOR toy_cur IS  
  6.         select toyprice from toys   
  7.         where toyprice < 250;   
  8. begin  
  9.     open toy_cur; --打开游标   
  10.     LOOP --循环   
  11.         --循环提取玩具的价格并给变量my_toy_price赋值   
  12.         fetch toy_cur into my_toy_price;   
  13.         --当查询没有返回任何行时退出循环   
  14.         exit when toy_cur%NOTFOUND;   
  15.         --输出玩具价格   
  16.         DBMS_OUTPUT.PUT_LINE(toy_cur%ROWCOUNT || '. 玩具单价:' || my_toy_price);   
  17.     END LOOP;   
  18.     --关闭游标   
  19.     close toy_cur;   
  20. end;   
  21. /  
set serveroutput on
declare
    --定义变量my_toy_price,其类型与toyprice字段一致
    my_toy_price toys.toyprice%TYPE;
    CURSOR toy_cur IS
        select toyprice from toys
        where toyprice < 250;
begin
    open toy_cur; --打开游标
    LOOP --循环
        --循环提取玩具的价格并给变量my_toy_price赋值
        fetch toy_cur into my_toy_price;
        --当查询没有返回任何行时退出循环
        exit when toy_cur%NOTFOUND;
        --输出玩具价格
        DBMS_OUTPUT.PUT_LINE(toy_cur%ROWCOUNT || '. 玩具单价:' || my_toy_price);
    END LOOP;
    --关闭游标
    close toy_cur;
end;
/

 

使用2: 用游标操作PRODUCTDETAILS表,

Sql代码 复制代码  收藏代码
  1. declare  
  2.     --定义变量pro_price,其类型与PRODPRICE字段一致   
  3.     pro_price PRODUCTDETAILS.PRODPRICE%TYPE;   
  4.     --定义变量pro_name,其类型与PRODNAME字段一致   
  5.     pro_name PRODUCTDETAILS.PRODNAME%TYPE;   
  6.     --定义游标pro_cur,查询所有价格小于5000的商品   
  7.     CURSOR pro_cur IS  
  8.         select PRODNAME, PRODPRICE from PRODUCTDETAILS   
  9.         where PRODPRICE < 5000;   
  10. begin  
  11.     open pro_cur; --打开游标   
  12.     LOOP --循环   
  13.         --循环提取商品的名称和价格并赋值给变量pro_name和pro_price   
  14.         fetch pro_cur into pro_name, pro_price;   
  15.         --当查询没有返回任何行时退出循环   
  16.         exit when pro_cur%NOTFOUND;   
  17.         --输出商品名、价格   
  18.         DBMS_OUTPUT.PUT_LINE(pro_cur%ROWCOUNT || ', 商品名:' || pro_name || ', 单价:' || pro_price);   
  19.     END LOOP;   
  20.     --关闭游标   
  21.     close pro_cur;   
  22. end;   
  23. /  
declare
    --定义变量pro_price,其类型与PRODPRICE字段一致
    pro_price PRODUCTDETAILS.PRODPRICE%TYPE;
    --定义变量pro_name,其类型与PRODNAME字段一致
    pro_name PRODUCTDETAILS.PRODNAME%TYPE;
    --定义游标pro_cur,查询所有价格小于5000的商品
    CURSOR pro_cur IS
        select PRODNAME, PRODPRICE from PRODUCTDETAILS
        where PRODPRICE < 5000;
begin
    open pro_cur; --打开游标
    LOOP --循环
        --循环提取商品的名称和价格并赋值给变量pro_name和pro_price
        fetch pro_cur into pro_name, pro_price;
        --当查询没有返回任何行时退出循环
        exit when pro_cur%NOTFOUND;
        --输出商品名、价格
        DBMS_OUTPUT.PUT_LINE(pro_cur%ROWCOUNT || ', 商品名:' || pro_name || ', 单价:' || pro_price);
    END LOOP;
    --关闭游标
    close pro_cur;
end;
/

 


5、使用显示游标删除或更新

语法:cursor cursor_name is select语句 for update [of colums];
注意:select语句只能包括一个表

游标声明中使用FOR UPDATE子句后,可使用以下语法更新行:

update 表名 set column_name = column_value
where CURRENT OF cursor_name;

注意:update命令中使用的列也必须出现在for update of子句中,
update和delete语句只有在打开游标并提取到特定行后才能使用


使用: 用显示游标更新行,将所有价格低于100的玩具提价10%,

Sql代码 复制代码  收藏代码
  1. set serveroutput on  
  2. declare  
  3.     new_price number;   
  4.     --定义游标   
  5.     cursor cur_toy is  
  6.     select toyprice from toys where toyprice < 100 for update of toyprice;   
  7. begin  
  8.     open cur_toy;--打开游标   
  9.     LOOP   
  10.         --执行SQL查询语句,提取价格并赋值给变量new_price   
  11.         fetch cur_toy into new_price;   
  12.         --如果没有查询结果,退出循环   
  13.         exit when cur_toy%NOTFOUND;   
  14.         --给价格低于100的商品提价10%   
  15.         update toys set toyprice = 1.1 * new_price where CURRENT OF cur_toy;   
  16.     end loop;   
  17.     close cur_toy;   
  18.     commit;   
  19. end;   
  20. /  
set serveroutput on
declare
    new_price number;
    --定义游标
    cursor cur_toy is
    select toyprice from toys where toyprice < 100 for update of toyprice;
begin
    open cur_toy;--打开游标
    LOOP
        --执行SQL查询语句,提取价格并赋值给变量new_price
        fetch cur_toy into new_price;
        --如果没有查询结果,退出循环
        exit when cur_toy%NOTFOUND;
        --给价格低于100的商品提价10%
        update toys set toyprice = 1.1 * new_price where CURRENT OF cur_toy;
    end loop;
    close cur_toy;
    commit;
end;
/

 


6、带参的显示游标

显示游标可以接受输入的参数,声明带参游标的语法 如下:

CURSOR cursor_name (<param_name> data_type)
[return <return_type>]

IS

select_statement;

使用: 提示输入部门编号,根据输入的部门编号提取该部门
下的员工,显示员工的编号和姓名,

Sql代码 复制代码  收藏代码
  1. declare  
  2.     dept_code emp.deptno%TYPE;   
  3.     emp_code emp.empno%TYPE;   
  4.     emp_name emp.ename%TYPE;   
  5.     --定义带参游标,参数名为deptparam,查询指定部门的员工   
  6.     cursor emp_cur (deptparam number) is  
  7.         select empno, ename from emp   
  8.         where deptno=deptparam;--查询条件使用参数匹配   
  9. begin  
  10.     --输入部门编号   
  11.     dept_code := '&部门编号';   
  12.     open emp_cur(dept_code);--打开游标的同时传参   
  13.     LOOP --循环   
  14.         --取出员工编号、员工名并赋值给变量emp_code、emp_name   
  15.         fetch emp_cur into emp_code, emp_name;   
  16.         --没有查询出结果退出循环   
  17.         exit when emp_cur%NOTFOUND;   
  18.         --系统输出   
  19.         DBMS_OUTPUT.PUT_LINE(emp_code || ' ' || emp_name);   
  20.     END LOOP;   
  21.     --关闭游标   
  22.     close emp_cur;   
  23. end;   
  24. /  
declare
    dept_code emp.deptno%TYPE;
    emp_code emp.empno%TYPE;
    emp_name emp.ename%TYPE;
    --定义带参游标,参数名为deptparam,查询指定部门的员工
    cursor emp_cur (deptparam number) is
        select empno, ename from emp
        where deptno=deptparam;--查询条件使用参数匹配
begin
    --输入部门编号
    dept_code := '&部门编号';
    open emp_cur(dept_code);--打开游标的同时传参
    LOOP --循环
        --取出员工编号、员工名并赋值给变量emp_code、emp_name
        fetch emp_cur into emp_code, emp_name;
        --没有查询出结果退出循环
        exit when emp_cur%NOTFOUND;
        --系统输出
        DBMS_OUTPUT.PUT_LINE(emp_code || ' ' || emp_name);
    END LOOP;
    --关闭游标
    close emp_cur;
end;
/

 


7、使用循环游标简化显示游标的代码

当用户需要从游标中提取所有记录时使用循环游标,可自动从结果集
中获取行,处理完所有行后关闭游标,循环游标还自动创建%ROWTYPE
类型的变量并将该变量作为记录索引,语法 如下:

FOR row_record IN cursor_name
LOOP
    语句;
END LOOP ;

语法说明:
row_record,保存行记录的变量,为%ROWTYPE类型,FOR循环外不能访问
cursor_name,游标名称

循环游标的特点:

  • 在从游标中提取了所有记录后自动终止
  • 可提取和处理游标中的每一条记录
  • 如果在提前记录后%NOTFOUND属性返回true,会终止循环,如果没有
    返回任何行,不会进入循环


使用: 输出显示所有玩具的编号、名称、价格,

Sql代码 复制代码  收藏代码
  1. SET SERVER OUTPUT ON  
  2. DECLARE  
  3.       CURSOR mytoyCur IS  
  4.         SELECT toyid, toyname, toyprice   
  5.         FROM toys;   
  6. BEGIN  
  7.       FOR toyRec IN mytoyCur   
  8.       LOOP   
  9.             DBMS_OUTPUT.PUT_LINE(   
  10.                          '玩具编号:' || ' ' || toyRec.toyid||' '              
  11.             || ‘玩具名称:' || ' '|| toyRec.toyname||' '   
  12.             || ‘玩具单价:' || ' '||toyRec.toyprice);   
  13.       END LOOP;   
  14. END;   
  15. /  
SET SERVER OUTPUT ON
DECLARE
      CURSOR mytoyCur IS
        SELECT toyid, toyname, toyprice
        FROM toys;
BEGIN
      FOR toyRec IN mytoyCur
      LOOP
            DBMS_OUTPUT.PUT_LINE(
                         '玩具编号:' || ' ' || toyRec.toyid||' '           
            || ‘玩具名称:' || ' '|| toyRec.toyname||' '
            || ‘玩具单价:' || ' '||toyRec.toyprice);
      END LOOP;
END;
/

 

处理带参的循环游标语法如下:

FOR row_record IN cursor_name (parameters)
LOOP
    语句;
END LOOP ;

8、REF 游标和游标变量

隐式/显示游标在使用它们的时候查询语句已确定,如需在运行时动态
决定执行什么查询,可使用REF游标和游标变量

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

  • 声明REF游标类型
  • 声明REF游标类型的变量


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

    TYPE ref_cursor_name
    IS REF CURSOR
    [RETURN return_type];

语法说明:

return可选子句用于指定游标提取结果集的返回类型,如果
包含return子句表示强类型REF游标,不包含return则为弱
类型REF游标

定义好游标、游标变量后,可在PL/SQL的执行部分打开REF游标,语法为:
OPEN cursor_name FOR select_statement;
注意:提取和关闭游标的语法与显示游标相似

使用: 接收用户输入,选择查看员工信息或者部门信息,

Sql代码 复制代码  收藏代码
  1. set serveroutput on  
  2. --accept命令可接收用户输入并存入变量tab中   
  3. ACCEPT tab PROMPT '你想查看什么信息?员工信息(E),部门信息(D):';   
  4. DECLARE  
  5.     --声明REF游标(弱类型)   
  6.     TYPE refCurT IS REF CURSOR;   
  7.     --声明游标变量refCur   
  8.     refCur refCurT;   
  9.     pId number;   
  10.     pName varchar2(100);   
  11.     --定义变量selection保存用户输入的字符(E或D)   
  12.     selection varchar2(1) := UPPER(SUBSTR('&tab'), 1, 1);   
  13. BEGIN  
  14.     --判断用户输入的是不是'E'   
  15.     IF selection = 'E' THEN  
  16.         --打开游标,同时指定select语句   
  17.         OPEN refCur FOR  
  18.             --查询员工表   
  19.             select empNo id, empName name  
  20.             from emp;   
  21.         --准备显示员工信息   
  22.         DBMS_OUTPUT.PUT_LINE('===员工信息===');   
  23.     ELSIF selection = 'D' THEN  
  24.         --打开游标,同时指定select语句   
  25.         OPEN refCur FOR  
  26.             --查询部门表   
  27.             select depNo id, depName name  
  28.             from dept;   
  29.         --准备显示部门信息   
  30.         DBMS_OUTPUT.PUT_LINE('===部门信息===');   
  31.     ELSE  
  32.         --提示输入   
  33.         DBMS_OUTPUT.PUT_LINE('请输入员工信息(E) 或 部门信息(D)');   
  34.         RETURN;   
  35.     END IF;   
  36.     --从游标中提取编号、名称,赋值给变量pId、pName   
  37.     FETCH refCur INTO pId, pName;   
  38.     --循环提取所有信息并显示   
  39.     WHILE refCur%FOUND LOOP   
  40.         --显示信息   
  41.         DBMS_OUTPUT.PUT_LINE('编号:' || pId || ' 名字:' || pName);   
  42.         --从游标中提取编号、名称,赋值给变量pId、pName   
  43.         FETCH refCur INTO pId, pName;   
  44.     END LOOP;   
  45.     --关闭游标   
  46.     CLOSE refCur;   
  47. END;   
  48. /  
set serveroutput on
--accept命令可接收用户输入并存入变量tab中
ACCEPT tab PROMPT '你想查看什么信息?员工信息(E),部门信息(D):';
DECLARE
    --声明REF游标(弱类型)
    TYPE refCurT IS REF CURSOR;
    --声明游标变量refCur
    refCur refCurT;
    pId number;
    pName varchar2(100);
    --定义变量selection保存用户输入的字符(E或D)
    selection varchar2(1) := UPPER(SUBSTR('&tab'), 1, 1);
BEGIN
    --判断用户输入的是不是'E'
    IF selection = 'E' THEN
        --打开游标,同时指定select语句
        OPEN refCur FOR
            --查询员工表
            select empNo id, empName name
            from emp;
        --准备显示员工信息
        DBMS_OUTPUT.PUT_LINE('===员工信息===');
    ELSIF selection = 'D' THEN
        --打开游标,同时指定select语句
        OPEN refCur FOR
            --查询部门表
            select depNo id, depName name
            from dept;
        --准备显示部门信息
        DBMS_OUTPUT.PUT_LINE('===部门信息===');
    ELSE
        --提示输入
        DBMS_OUTPUT.PUT_LINE('请输入员工信息(E) 或 部门信息(D)');
        RETURN;
    END IF;
    --从游标中提取编号、名称,赋值给变量pId、pName
    FETCH refCur INTO pId, pName;
    --循环提取所有信息并显示
    WHILE refCur%FOUND LOOP
        --显示信息
        DBMS_OUTPUT.PUT_LINE('编号:' || pId || ' 名字:' || pName);
        --从游标中提取编号、名称,赋值给变量pId、pName
        FETCH refCur INTO pId, pName;
    END LOOP;
    --关闭游标
    CLOSE refCur;
END;
/

 


9、使用REF游标执行动态SQL语句

EXECUTE IMMEDIATE语句只能处理返回单行或没有返回的SQL语句,
REF游标可处理返回结果集的动态SQL,语法如下:

OPEN cursor_name

FOR
动态SQL语句字符串
[USING 绑定的输入参数]

注意:这种游标,声明部分与普通REF游标相同,只是OPEN语法不一样

使用: 显示薪水高于2500的员工信息,

Sql代码 复制代码  收藏代码
  1. SET SERVEROUTPUT ON  
  2. VARIABLE maxSal NUMBER   
  3. EXECUTE :maxSal := 2500   
  4. DECLARE  
  5.     empRec emp%ROWTYPE;   
  6.     --定义REF游标   
  7.     TYPE cType IS REF CURSOR;   
  8.     --定义游标变量   
  9.     cur cType;   
  10.     --薪水   
  11.     pSalary number;   
  12. BEGIN  
  13.     pSalary := :maxSal;   
  14.     --打开游标,设置SQL字符串   
  15.     OPEN cur FOR  
  16.     'select * from Emp where sal > :inputSal order by sal desc';   
  17.     USING pSalary --使用变量pSalary的值作为输入参数传递给:inputSal   
  18.     --循环显示出所有薪水大于指定值的员工   
  19.     LOOP   
  20.         --使用游标提取行   
  21.         FETCH cur INTO empRec;   
  22.         --判断所有行是否读取完毕,读取完毕需退出循环   
  23.         EXIT WHEN cur%NOTFOUND;   
  24.         --显示信息   
  25.         DBMS_OUTPUT.PUT_LINE('编号:' || empRec.empNo   
  26.         || ' 姓名:' || empRec.eName || ' 薪水:' || empRec.sal);   
  27.     END LOOP;   
  28.     --关闭游标   
  29.     CLOSE cur;   
  30. END;   
  31. /  
SET SERVEROUTPUT ON
VARIABLE maxSal NUMBER
EXECUTE :maxSal := 2500
DECLARE
    empRec emp%ROWTYPE;
    --定义REF游标
    TYPE cType IS REF CURSOR;
    --定义游标变量
    cur cType;
    --薪水
    pSalary number;
BEGIN
    pSalary := :maxSal;
    --打开游标,设置SQL字符串
    OPEN cur FOR
    'select * from Emp where sal > :inputSal order by sal desc';
    USING pSalary --使用变量pSalary的值作为输入参数传递给:inputSal
    --循环显示出所有薪水大于指定值的员工
    LOOP
        --使用游标提取行
        FETCH cur INTO empRec;
        --判断所有行是否读取完毕,读取完毕需退出循环
        EXIT WHEN cur%NOTFOUND;
        --显示信息
        DBMS_OUTPUT.PUT_LINE('编号:' || empRec.empNo
        || ' 姓名:' || empRec.eName || ' 薪水:' || empRec.sal);
    END LOOP;
    --关闭游标
    CLOSE cur;
END;
/

 


10、游标变量的优点和限制


游标变量的优点 有:

  • 可从不同的SELECT语句中提取结果集
  • 可以作为过程的参数进行传递
  • 可以引用游标的所有属性
  • 可以进行赋值运算


使用游标变量的限制:

  • 不能在程序包中声明游标变量
  • FOR UPDATE子句不能与游标变量一起使用
  • 不能使用比较运算符


11、总结

  • 游标用于处理查询结果集中的数据
  • 游标类型有:隐式游标、显式游标 和 REF 游标
  • 隐式游标由PL/SQL自动定义、打开和关闭
  • 显式游标用于处理返回多行的查询
  • 显式游标可以删除和更新活动集中的行
  • 要处理结果集中所有记录时,可使用循环游标
  • 在声明REF游标时,不需要将 SELECT 语句与其关联
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值