源码-PL/SQL从入门到精通-第十章-使用游标-Part 2

虽说下个项目中要用到PL/SQL,但还不清楚需要用到哪些具体的知识点?估计游标是不可或缺了,如果能在现有代码的基础上改一改就能满足项目要求,现在的工作也就更有价值了。

--代码10.14 基本的Loop循环结构
DECLARE
   dept_row dept%ROWTYPE;                      --定义游标结果记录变量
   CURSOR dept_cursor IS SELECT * FROM dept;   --定义游标变量
BEGIN
   OPEN dept_cursor;                           --打开游标
   LOOP                                        --简单循环
      FETCH dept_cursor INTO dept_row;         --提取游标数据
      EXIT WHEN dept_cursor%NOTFOUND;          --退出循环的控制语句
      DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);
   END LOOP;
   CLOSE dept_cursor;                          --关闭游标
END;   

--代码10.15 使用WHILE循环循环检索游标数据
DECLARE
   dept_row dept%ROWTYPE;                      --定义游标结果记录变量
   CURSOR dept_cursor IS SELECT * FROM dept;   --定义游标变量
BEGIN
   OPEN dept_cursor;                           --打开游标
   FETCH dept_cursor INTO dept_row;            --提取游标数据
   WHILE dept_cursor%FOUND  LOOP
      DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);
      FETCH dept_cursor INTO dept_row;         --提取游标数据
   END LOOP;
   CLOSE dept_cursor;                          --关闭游标
END;   

--代码10.16 使用游标For循环检索数据
DECLARE
   CURSOR dept_cursor IS SELECT * FROM dept;   --定义游标变量
BEGIN
   FOR dept_row IN dept_cursor LOOP            --在游标FOR循环中检索数据
     DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);
   END LOOP;
END;   

--代码10.17 游标For循环子查询语句(简洁就是好!)
BEGIN
   FOR dept_row IN (SELECT * FROM dept) LOOP    --在游标FOR循环中检索数据
     DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);
   END LOOP;
END;   

--代码10.18 使用游标更新数据
DECLARE
   CURSOR emp_cursor (p_deptno IN NUMBER)
   IS
      SELECT  *
            FROM emp
           WHERE deptno = p_deptno
      FOR UPDATE;                              --使用FOR UPDATE子句添加互斥锁
BEGIN
   FOR emp_row IN emp_cursor (20)              --使用游标FOR循环检索游标
   LOOP
      UPDATE emp
         SET comm = comm * 1.12
       WHERE CURRENT OF emp_cursor;            --使用WHERE CURRENT OF更新游标数据
   END LOOP;
   COMMIT;                                     --提交更改
END;

--代码10.18 使用游标删除数据
DECLARE
   CURSOR emp_cursor (p_empno IN NUMBER)
   IS
      SELECT  *
            FROM emp
           WHERE empno = p_empno
      FOR UPDATE;                              --使用FOR UPDATE子句添加互斥锁
BEGIN
   FOR emp_row IN emp_cursor (7369)              --使用游标FOR循环检索游标
   LOOP
    DELETE FROM emp
       WHERE CURRENT OF emp_cursor;            --使用WHERE CURRENT OF删除游标数据
   END LOOP;
END;

--代码10.20 游标变量使用示例
DECLARE
   TYPE emp_type IS REF CURSOR RETURN emp%ROWTYPE;       --定义游标变量类型
   emp_cur   emp_type;                                   --声明游标变量
   emp_row   emp%ROWTYPE;                                --定义游标结果值变量
BEGIN
   OPEN emp_cur FOR SELECT * FROM emp;                   --打开游标
   LOOP
      FETCH emp_cur INTO emp_row;                        --循环提取游标数据
      EXIT WHEN emp_cur%NOTFOUND;                        --循环退出检测
      DBMS_OUTPUT.put_line ('员工名称:' || emp_row.ename);
   END LOOP;
END;

--代码10.21 定义游标变量
DECLARE
   TYPE emp_type IS REF CURSOR RETURN emp%ROWTYPE;      --定义游标类型
   TYPE gen_type IS REF CURSOR;
   emp_cur emp_type;                                   --声明游标变量
   gen_cur gen_type;
BEGIN
   OPEN emp_cur FOR SELECT * FROM emp WHERE deptno=20;
END;   

DECLARE
    gen_type SYS_REFCURSOR;
BEGIN
END;       

--代码10.22 大咖游标变量示例
DECLARE
   TYPE emp_curtype IS REF CURSOR;                       --定义游标类型
   emp_cur emp_curtype;                                  --声明游标类型的变量
BEGIN
   OPEN emp_cur FOR SELECT * FROM emp;                   --打开游标,查询emp所有列
   OPEN emp_cur FOR SELECT empno FROM emp;               --打开游标,查询emp表empno列
   OPEN emp_cur FOR SELECT deptno FROM dept;             --打开游标,查询dept表deptno列
END;

--使用Fetch语句提取游标变量数据
DECLARE
   TYPE emp_type IS REF CURSOR RETURN emp%ROWTYPE;       --定义游标类型
   emp_cur emp_type;                                     --声明游标变量
   emp_row emp%ROWTYPE;
BEGIN
   IF NOT emp_cur%ISOPEN THEN                            --如果游标变量没有打开
   OPEN emp_cur FOR SELECT * FROM emp WHERE deptno=20;   --打开游标变量
   END IF;
   LOOP
     FETCH emp_cur INTO emp_row;                         --提取游标变量
     EXIT WHEN emp_cur%NOTFOUND;                         --如果提取完成则退出循环
     DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename
                         ||' 员工职位:'||emp_row.job);  --输出员工信息
   END LOOP;
END;   

--使用close语句关闭游标变量(不关闭也不会报错)
DECLARE
   TYPE emp_type IS REF CURSOR RETURN emp%ROWTYPE;       --定义游标类型
   emp_cur emp_type;                                     --声明游标变量
   emp_row emp%ROWTYPE;
BEGIN
   OPEN emp_cur FOR SELECT * FROM emp WHERE deptno=20;   --打开游标
   FETCH emp_cur INTO emp_row;                           --提取游标
   WHILE emp_cur%FOUND LOOP                              --循环提取游标
     DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename);
     FETCH emp_cur INTO emp_row;
   END LOOP;
   CLOSE emp_cur;                                        --关闭游标
END;   

--以下代码不能通过编译(使用fetch语句前,应先使用open语句)
DECLARE
   TYPE emp_curtype IS REF CURSOR;                       --定义游标类型
   emp_cur emp_curtype;                                  --声明游标类型的变量
   emp_row emp%ROWTYPE;
BEGIN
   FETCH emp_cur INTO emp_row;
END;

--代码10.25 处理Invalid_cursor异常(不太明白)
DECLARE
   TYPE emp_curtype IS REF CURSOR;                       --定义游标类型
   emp_cur1 emp_curtype;                                 --声明游标类型的变量
   emp_cur2 emp_curtype;
   emp_row emp%ROWTYPE;                                  --定义保存游标数据的记录类型
BEGIN
   OPEN emp_cur1 FOR SELECT * FROM emp WHERE deptno=20;  --打开第1个游标
   FETCH emp_cur1 INTO emp_row;                          --提取并显示游标信息
   DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename||' 部门编号:'||emp_row.deptno);
   FETCH emp_cur2 INTO emp_row;                          --提取第2个游标变量将引发异常
EXCEPTION
   WHEN INVALID_CURSOR THEN                              --异常处理
      emp_cur2:=emp_cur1;                                --将emp_cur1指向的查询区域赋给emp_cur2
      FETCH emp_cur2 INTO emp_row;                       --现在emp_cur1与emp_cur2指向相同的查询
      DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename||' 部门编号:'||emp_row.deptno);
      OPEN emp_cur2 FOR SELECT * FROM emp WHERE deptno=30; --重新打开emp_cur2游标变量,利用相同的查询区域
      FETCH emp_cur1 INTO emp_row;                         --由于emp_cur1与emp_cur2共享相同的查询区域,因此结果相同
      DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename||' 部门编号:'||emp_row.deptno);
END;

--处理Rowtype_mismatch异常
DECLARE
   TYPE emp_curtype IS REF CURSOR;                       --定义游标类型
   emp_cur emp_curtype;                                  --声明游标类型的变量
   emp_row emp%ROWTYPE;                                  --声明游标数据结果类型
   dept_row dept%ROWTYPE;
BEGIN
   OPEN emp_cur FOR SELECT * FROM emp WHERE deptno=20;   --打开游标变量
   FETCH emp_cur INTO dept_row;                          --提取到一个不匹配的类型中
EXCEPTION
   WHEN ROWTYPE_MISMATCH THEN                            --处理ROWTYPE_MISMATCH异常
     FETCH emp_cur INTO emp_row;                         --再次提取游标变量数据,输出结果
     DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename||' 部门编号:'||emp_row.deptno);
END;

--使用Sys_refcursor类型
DECLARE
   emp_cur SYS_REFCURSOR;                               --定义弱类型游标变量
   emp_row emp%ROWTYPE;
   dept_row dept%ROWTYPE;
BEGIN
   OPEN emp_cur FOR SELECT * FROM emp WHERE deptno=20;  --打开游标数据
   FETCH emp_cur INTO dept_row;
EXCEPTION
   WHEN ROWTYPE_MISMATCH THEN                           --处理ROWTYPE_MISMATCH异常
     FETCH emp_cur INTO emp_row;                        --重新提取并输出异常结果
     DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename||' 部门编号:'||emp_row.deptno);
END;

--代码10.28 在包中使用游标变量
--创建包规范
CREATE OR REPLACE PACKAGE emp_data_action AS
   TYPE emp_type IS REF CURSOR RETURN emp%ROWTYPE;         --定义强类型游标类型
   --定义使游标变量的子程序
   PROCEDURE getempbydeptno(emp_cur IN OUT emp_type,p_deptno NUMBER);
END emp_data_action;

--实现包体
CREATE OR REPLACE PACKAGE BODY emp_data_action AS
   --创建在包规范中定义的过程
   PROCEDURE getempbydeptno(emp_cur IN OUT emp_type,p_deptno NUMBER) IS
     emp_row emp%ROWTYPE;
   BEGIN
     OPEN emp_cur FOR SELECT * from emp WHERE deptno=p_deptno;  --打开游标变量
     LOOP
       FETCH emp_cur INTO emp_row;                              --提取数据
       EXIT WHEN emp_cur%NOTFOUND;
       --输出游标数据
       DBMS_OUTPUT.PUT_LINE('员工名称:'||emp_row.ename||' 部门编号:'||emp_row.deptno);
     END LOOP;
     CLOSE emp_cur;
   END;
END emp_data_action;

DECLARE
   emp_cursors   emp_data_action.emp_type;         --定义在包中定义的游标类型
BEGIN
   emp_data_action.getempbydeptno (emp_cursors, 20);   --调用在包中定义的过程
END;

--创建包规范
CREATE OR REPLACE PACKAGE emp_data_action_err AS
   TYPE emp_type IS REF CURSOR RETURN emp%ROWTYPE;         --定义强类型游标类型
   emp_cur emp_type;
   --定义使游标变量的子程序
   PROCEDURE getempbydeptno(emp_cur IN OUT emp_type,p_deptno NUMBER);
END emp_data_action_err;

DECLARE
   TYPE emp_curtype IS REF CURSOR;                       --定义游标类型
   emp_cur emp_curtype;                                  --声明游标类型的变量
BEGIN
   FOR emp_row IN emp_cur LOOP
      DBMS_OUTPUT.PUT_LINE(emp_row.ename);
   END LOOP;
END;
时间: 2024-10-06 01:15:02

源码-PL/SQL从入门到精通-第十章-使用游标-Part 2的相关文章

源码-PL/SQL从入门到精通-第二章-PL/SQL基本概念-Part 1

随书附带的源码没有序号,部分有bug,调试过程中一并更正. --代码2.1 使用书序结构计算员工薪资 DECLARE v_sal1 NUMBER; v_sal2 NUMBER; v_sumsal NUMBER; BEGIN SELECT sal INTO v_sal1 FROM emp WHERE empno = &empno1; SELECT sal INTO v_sal2 FROM emp WHERE empno = &empno2; v_sumsal := v_sal1 + v_sa

源码-PL/SQL从入门到精通-第四章-PL/SQL控制语句(基础中的基础)

控制语句对任何一门语言.任何一个程序员而言,都是基础中的基础. 学了PL/SQL,才体会到Java语法的简洁,简直不是一个时代的东西:当然,他们的定位本来就不一样,不能以己之长比之他人之短. --第4章开始 --代码4.1 最简单的IF语句使用示例 DECLARE v_count NUMBER(10) := 0; --定义计数器变量 v_empno NUMBER(4) := 7888; --定义员工编号 BEGIN SELECT COUNT(1) --首先查询指定的员工编号是否存在 INTO v

源码-PL/SQL从入门到精通-第十三章-子程序-Part 2

调试nocopy功能时,为了看到实际效果,设置了一个比较大的循环次数,结果悲剧了: 运行了近1个小时没出结果,电脑死机(任务管理器都打不开):无奈只能强行关机,开机时间又特别长,一度让我以为系统崩溃. 看来,PL/SQL developer下调试这种暴力计算的程序风险很高啊,我在Eclipse下调试Java程序时从来没碰到过这种造成电脑死机的情况. 不过,这章的内容实用性很强,死机也值了(有点心疼电脑了) -代码13.11 使用%Type定义形式参数 CREATE OR REPLACE PROC

源码-PL/SQL从入门到精通-第七章-操作数据表

除了序列(Sequence)和同义词(Synonym)外,其他语句基本上都在自己创建的iTerm数据中用过了,所以这章感觉不难. --第7章开始 --7.1.2 插入单行记录 SELECT * FROM emp; INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno ) VALUES (7890, '刘七', '副理', 7566, TO_DATE ('2001-08-15', 'YYYY-MM-DD'), 80

MyBatis源码分析-SQL语句执行的完整流程

MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录.如何新建MyBatis源码工程请点击MyBatis源码分析-IDEA新建MyBatis源码工程. MyBatis框架主要完成的是以下2件事情: 根据JD

Oracle PL/SQL语言入门

简介:PL/SQL(Procedural Language/Structured Query Language)是一种过程化语言,属于第三代语言,它与C.C++.Java等语言一样关注于处理细节,可以用来实现比较复杂的业务逻辑.它允许SQL的数据操纵语言和查询语句包含在块结构(block_structured)和代码过程语言中,使PL/SQL成为一个功能强大的事务处理语言. 一.背景介绍 结构化查询语言(Structured Query Language,简称SQL)是用来访问关系型数据库一种通

数据库分库分表中间件 Sharding-JDBC 源码分析 —— SQL 解析(六)之删除SQL

关注微信公众号:[芋道源码]有福利: RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表 RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址 您对于源码的疑问每条留言都将得到认真回复.甚至不知道如何读源码也可以请教噢. 新的源码解析文章实时收到通知.每周更新一篇左右. 认真的源码交流微信群. 本文主要基于 Sharding-JDBC 1.5.0 正式版 1. 概述 2. DeleteStatement 3. #p

数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(二)之SQL解析

关注微信公众号:[芋艿的后端小屋]有福利: RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表 RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址 您对于源码的疑问每条留言都将得到认真回复.甚至不知道如何读源码也可以请教噢. 新的源码解析文章实时收到通知.每周更新一篇左右. 认真的源码交流微信群. 1. 概述 2. SQLParsingEngine 3. SQLParser SQL解析器 3.2.1 #parse

数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(一)之语法解析

关注微信公众号:[芋艿的后端小屋]有福利: RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表 RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址 您对于源码的疑问每条留言都将得到认真回复.甚至不知道如何读源码也可以请教噢. 新的源码解析文章实时收到通知.每周更新一篇左右. 1. 概述 2. Lexer 词法解析器 3. Token 词法标记 3.2.1 Literals.IDENTIFIER 词法关键词 3.2