第十一章:游标_游标的属性值-程序员宅基地

技术标签: oracle  Oracle  数据库  

什么是游标?

游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块

显示游标的处理:

--查询所有员工的员工号、姓名和职位的信息。
DECLARE
  --定义游标
  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp;
  v_empno emp.empno%TYPE;
  v_ename emp.ename%TYPE;
  v_job   emp.job%TYPE;
BEGIN
  --打开游标,执行查询
  OPEN emp_cursor;
  --提取数据  
  LOOP
       FETCH emp_cursor INTO v_empno,v_ename,v_job;
       DBMS_OUTPUT.PUT_LINE('员工号:'||v_empno||',姓名:'||v_ename||',职位:'||v_job);
       --什么时候能够退出循环?
       --%FOUND,%NOTFOUND
       EXIT WHEN emp_cursor%NOTFOUND;       
  END LOOP;
  --关闭游标
  CLOSE emp_cursor;
END;
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

显示游标的四个属性:

  • %FOUND:该属性用于检测游标结果集是否存在数据,如果存在数据,返回TRUE。
  • %NOTFOUND:该属性用于检测游标结果集是否不存在数据,如果不存在数据,返回TRUE。
  • %ISOPEN:该属性用于检测游标是否已经打开,如果已经打开返回TRUE。
  • %ROWCOUNT:该属性用于返回已提取的实际行数。
--查询所有员工的员工号、姓名和职位的信息。
DECLARE
  --定义游标
  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp;
  v_empno emp.empno%TYPE;
  v_ename emp.ename%TYPE;
  v_job   emp.job%TYPE;
BEGIN
  --打开游标,执行查询
  OPEN emp_cursor;
  --提取数据  
  LOOP
       FETCH emp_cursor INTO v_empno,v_ename,v_job;
       DBMS_OUTPUT.PUT_LINE('员工号:'||v_empno||',姓名:'||v_ename||',职位:'||v_job);
       --什么时候能够退出循环?
       --%FOUND,%NOTFOUND
       --EXIT WHEN emp_cursor%NOTFOUND;
       --EXIT WHEN NOT emp_cursor%FOUND;
       EXIT WHEN emp_cursor%ROWCOUNT=5;
  END LOOP;
  --关闭游标
  CLOSE emp_cursor;
END;
 
--查询所有员工的员工号、姓名和职位的信息。
DECLARE
  --定义游标
  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp;
  v_empno emp.empno%TYPE;
  v_ename emp.ename%TYPE;
  v_job   emp.job%TYPE;
BEGIN
  --打开游标,执行查询
  --OPEN emp_cursor;
  --检测游标是否打开
  IF emp_cursor%ISOPEN THEN
    DBMS_OUTPUT.PUT_LINE('游标已经打开');
  ELSE
    DBMS_OUTPUT.PUT_LINE('游标没有打开');
  END IF;

END;


--按职工的职称涨工资,总裁涨1000元,经理涨500元,其他员工涨300元。
DECLARE
  --定义游标
  CURSOR empnew_cursor IS SELECT empno,job FROM empnew;
  v_empno empnew.empno%TYPE;
  v_job   empnew.job%TYPE;
BEGIN
  --打开游标
  OPEN empnew_cursor;
  --提取数据
  LOOP
    FETCH empnew_cursor INTO v_empno,v_job;
    IF v_job='PRESIDENT' THEN
      UPDATE empnew SET sal = sal + 1000 WHERE empno = v_empno;
    ELSIF v_job='MANAGER' THEN
      UPDATE empnew SET sal = sal + 500 WHERE empno = v_empno;
    ELSE
      UPDATE empnew SET sal = sal + 300 WHERE empno = v_empno;
    END IF;
    EXIT WHEN empnew_cursor%NOTFOUND;
  END LOOP;
  COMMIT;
  --关闭游标
  CLOSE empnew_cursor;
END;

SELECT * FROM empnew;
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

游标的FOR循环

当使用游标for循环时,Oracle会隐含地打开游标,提取数据并关闭游标。

参数游标:参数游标是指带有参数的游标。通过使用参数游标,使用不同参数值可以生成不同的游标结果集。

--需求:查询员工的员工号、姓名、职位
--显示游标的常规方式
DECLARE
  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp;
  v_empno emp.empno%TYPE;
  v_name  emp.ename%TYPE;
  v_job   emp.job%TYPE;
BEGIN
  OPEN emp_cursor;
  LOOP
    FETCH emp_cursor INTO v_empno,v_name,v_job;
    EXIT WHEN emp_cursor%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE('员工号:'||v_empno ||'姓名:'||v_name||'职位:'||v_job);
  END LOOP;
  CLOSE emp_cursor;
END;

--游标FOR循环
DECLARE
  CURSOR emp_cursor IS SELECT empno,ename,job FROM emp;
BEGIN
  FOR emp_record IN emp_cursor LOOP
    DBMS_OUTPUT.PUT_LINE('员工号:'||emp_record.empno||',姓名:'||emp_record.ename||',职位:'||emp_record.job);
  END LOOP;
END;
 
--游标FOR循环中引用子查询
BEGIN
  FOR emp_record IN (SELECT empno,ename,job FROM emp) LOOP
    DBMS_OUTPUT.PUT_LINE('员工号:'||emp_record.empno||',姓名:'||emp_record.ename||',职位:'||emp_record.job);
  END LOOP;
END;

--参数游标
DECLARE
  CURSOR emp_cursor(dno NUMBER) IS SELECT empno,ename,job FROM emp WHERE deptno = dno;
BEGIN
  FOR emp_record IN emp_cursor(&no) LOOP
    DBMS_OUTPUT.PUT_LINE('员工号:'||emp_record.empno||',姓名:'||emp_record.ename||',职位:'||emp_record.job);
  END LOOP;
END;
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

隐式游标的处理

  • 显示游标是由用户自定义的显示创建的游标,主要是用于对查询语句的处理。
  • 隐式游标是由系统隐含创建的游标,主要用于对非查询语句,如修改、删除等操作,则由Oracle系统自动地位这些操作设置游标并创建其工作区。对于隐式游标的操作,如定义、打开、取值及关闭操作,都由Oracle系统自动完成,无需用户进行处理。
  • 隐式游标的名字为SQL,这是由Oracle系统定义的。

DML操作和单行SELECT语句会使用隐式游标,它们是:

  • 插入操作:insert
  • 更新操作:update
  • 删除操作:delete
  • 单行查询操作:select...into

当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。注意:通过SQL游标名总是只能访问前一个DML操作或单行select操作的游标属性。

隐式游标的属性:

  • SQL%FOUND
  • SQL%NOTFOUND
  • SQL%ISOPEN
  • SQL%ROWCOUNT
--根据用户输入的员工号,更新指定员工的工资,比如工资涨100
--隐式游标
BEGIN
  UPDATE empnew SET sal = sal + 100 WHERE empno = &no;
  IF SQL%FOUND THEN
    DBMS_OUTPUT.put_line('成功修改员工的工资');
    COMMIT;
  ELSE
    DBMS_OUTPUT.put_line('修改员工工资失败!');
    ROLLBACK;
  END IF;
END;

SELECT * FROM empnew;

使用游标修改或删除数据 

为了对正在处理(查询)的行不被另外的用户改动,Oracle提供一个FOR UPDATE子句来对所选择的行进行锁定。

如果创建的游标需要执行更新或删除的操作,必须带有FOR UPDATE子句。FOR UPDATE子句会将游标提取出来的数据进行行级锁定,这样在本会话更新期间,其他用户的会话就不能对当前游标中的数据行进行更新操作。

--按职工的职称涨工资,总裁涨1000元,经理涨500元,其他员工涨300元。
--1:用显示游标的常规方式实现业务需求
DECLARE
  --定义游标
  CURSOR empnew_cursor IS SELECT empno,job FROM empnew;
  v_empno empnew.empno%TYPE;
  v_job   empnew.job%TYPE;
BEGIN
  --打开游标
  OPEN empnew_cursor;
  --提取数据
  LOOP
    FETCH empnew_cursor INTO v_empno,v_job;
    IF v_job='PRESIDENT' THEN
      UPDATE empnew SET sal = sal + 1000 WHERE empno = v_empno;
    ELSIF v_job='MANAGER' THEN
      UPDATE empnew SET sal = sal + 500 WHERE empno = v_empno;
    ELSE
      UPDATE empnew SET sal = sal + 300 WHERE empno = v_empno;
    END IF;
    EXIT WHEN empnew_cursor%NOTFOUND;
  END LOOP;
  COMMIT;
  --关闭游标
  CLOSE empnew_cursor;
END;

--2:用游标FOR循环的方式实现业务需求
DECLARE
  --定义游标
  CURSOR empnew_cursor IS SELECT empno,job FROM empnew; 
BEGIN
  FOR empnew_record IN empnew_cursor LOOP    
      DBMS_OUTPUT.put_line(empnew_record.empno||'----'||empnew_record.job);      
      IF empnew_record.job = 'PRESIDENT' THEN
        UPDATE empnew SET sal = sal + 1000 WHERE empno = empnew_record.empno;
      ELSIF empnew_record.job = 'MANAGER' THEN
        UPDATE empnew SET sal = sal + 500 WHERE empno = empnew_record.empno;
      ELSE
        UPDATE empnew SET sal = sal + 300 WHERE empno = empnew_record.empno;
      END IF;
  END LOOP;
  --COMMIT;
END;

select * from empnew for update;


--3:使用游标添加或删除数据时,定义游标时利用FOR UPDATE 子句可以将游标提取出来的数据进行行级锁定
DECLARE
  --定义游标
  CURSOR empnew_cursor IS SELECT empno,job FROM empnew FOR UPDATE; 
BEGIN
  FOR empnew_record IN empnew_cursor LOOP    
      DBMS_OUTPUT.put_line(empnew_record.empno||'----'||empnew_record.job);      
      IF empnew_record.job = 'PRESIDENT' THEN
        UPDATE empnew SET sal = sal + 1000 WHERE CURRENT OF empnew_cursor;
      ELSIF empnew_record.job = 'MANAGER' THEN
        UPDATE empnew SET sal = sal + 500 WHERE CURRENT OF empnew_cursor;
      ELSE
        UPDATE empnew SET sal = sal + 300 WHERE CURRENT OF empnew_cursor;
      END IF;
  END LOOP;
  COMMIT;
END;

SELECT * FROM empnew;

NOWAIT:用于指定不等待锁,如果发现所操作的数据行已经锁定,将不会等待,立即返回。

当游标子查询涉及到多张表时,如果在特定表上加行共享锁,那么需要使用OF子句。

--FOR UPDATE NOWAIT 不等待锁,如发现所操作的数据行已经锁定,将不会等待,立即返回
DECLARE
  --定义游标
  CURSOR empnew_cursor IS SELECT empno,job FROM empnew FOR UPDATE NOWAIT; 
BEGIN
  FOR empnew_record IN empnew_cursor LOOP    
      DBMS_OUTPUT.put_line(empnew_record.empno||'----'||empnew_record.job);      
      IF empnew_record.job = 'PRESIDENT' THEN
        UPDATE empnew SET sal = sal + 1000 WHERE CURRENT OF empnew_cursor;
      ELSIF empnew_record.job = 'MANAGER' THEN
        UPDATE empnew SET sal = sal + 500 WHERE CURRENT OF empnew_cursor;
      ELSE
        UPDATE empnew SET sal = sal + 300 WHERE CURRENT OF empnew_cursor;
      END IF;
  END LOOP;
  COMMIT;
END;

SELECT * FROM empnew;

--使用OF子句在特定表上加行共享锁 
DECLARE
       CURSOR empnew_cursor IS
              SELECT d.dname dname,e.ename ename 
              FROM empnew e join dept d on e.deptno = d.deptno
              WHERE e.deptno = &deptno
              FOR UPDATE OF e.deptno;
BEGIN
        FOR empnew_record IN empnew_cursor LOOP
            DBMS_OUTPUT.PUT_LINE('部门名称:'||empnew_record.dname||'员工名:'||empnew_record.ename);
            DELETE FROM empnew WHERE CURRENT OF empnew_cursor;
        END LOOP;
        COMMIT;
END;
              
SELECT * FROM empnew where deptno = 20;     

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44337241/article/details/104740179

智能推荐

前端开发之vue-grid-layout的使用和实例-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout

Power Apps-上传附件控件_powerapps点击按钮上传附件-程序员宅基地

文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件

C++ 面向对象(Object-Oriented)的特征 & 构造函数& 析构函数_"object(cnofd[\"ofdrender\"])十条"-程序员宅基地

文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"

修改node_modules源码,并保存,使用patch-package打补丁,git提交代码后,所有人可以用到修改后的_修改 node_modules-程序员宅基地

文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules

【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure-程序员宅基地

文章浏览阅读883次。【代码】【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure

整理5个优秀的微信小程序开源项目_微信小程序开源模板-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏97次。整理5个优秀的微信小程序开源项目。收集了微信小程序开发过程中会使用到的资料、问题以及第三方组件库。_微信小程序开源模板

随便推点

Centos7最简搭建NFS服务器_centos7 搭建nfs server-程序员宅基地

文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server

Springboot整合Mybatis-Plus使用总结(mybatis 坑补充)_mybaitis-plus ruledataobjectattributemapper' and '-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d

EECE 1080C / Programming for ECESummer 2022 Laboratory 4: Global Functions Practice_eece1080c-程序员宅基地

文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c

洛谷p4777 【模板】扩展中国剩余定理-程序员宅基地

文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...

android 退出应用没有走ondestory方法,[Android基础论]为何Activity退出之后,系统没有调用onDestroy方法?...-程序员宅基地

文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy

SylixOS快问快答_select函数 导致堆栈溢出 sylixos-程序员宅基地

文章浏览阅读894次。Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的_select函数 导致堆栈溢出 sylixos

推荐文章

热门文章

相关标签