文章目录

  • 游标
    • 游标概念
    • 游标优点
    • 游标分类
    • 静态游标的使用
      • 显示游标
        • 显示游标的属性
        • 遍历显示游标
        • 显示游标的FOR循环
        • 接收显式游标数据的数据类型(普通变量、记录变量、集合变量)
        • 通过游标更新、删除表的数据
        • 显式游标在开发中不多见的应用
      • 隐式游标
        • 隐式游标的属性
    • 动态游标的使用
      • 静态游标和动态游标的区别
    • 更新或删除当前游标数据

游标

游标概念

在 PL/SQL 块执行 SELECT/INSERT/UPDATE/DELETE 语句时,Oracle 会在内存中为其分配上下文区,而游标是指向该区域的指针

游标为应用程序提供了一种对具有多行数据查询结果集中的每一行单独处理的方案,是设计交互式应用程序的编程接口。

在每个用户会话中,可以同时打开多个游标,其数量由数据库初始化参数文件中的OPEN_CURSORS参数定义。

对于不同的 SQL 语句,游标的使用情况不同:

SQL语句 游标
非查询语句 隐式的
结果是单行的查询语句 隐式的或显示的
结果是多行的查询语句 显示的

游标优点

  • 游标允许应用程序对查询语句返回的行结果集中的每一行进行操作
  • 游标提供了对基于游标位置而对表中数据行进行修改或者更新的能力。

游标分类

  • 隐式游标:非用户显式声明的游标。

    • PL/SQL为SELECT INTO语句、INSERT语句、DELETE语句和UPDATE语句自动声明了隐式游标
  • 显式游标:是由用户声明和操作的游标。
  • 动态游标:用于处理运行时才确定的动态查询语句的结果

静态游标的使用

显示游标

显示游标的使用步骤:定义游标,打开游标,使用游标,关闭游标

  • 在 DECLARE 中定义显式游标:CURSOR cursor_name [(参数名 参数数据类型,…)] [RETURN 数据类型] IS 查询语句
  • 打开游标:OPEN 游标名(输入变量列表)
    • 打开游标语句执行与游标关联的查询,绑定输入变量,识别活动集并将游标指针置于第一行
    • PL/SQL程序不能用OPEN语句重复打开一个游标。
  • 取出数据:FETCH 游标名 INTO 变量列表
  • 关闭游标:CLOSE 游标名
--无参数无返回值游标 例子
DECLARECURSOR c_emp IS SELECT empno, ename FROM emp;v_empno emp.empno%TYPE;v_ename emp.ename%TYPE;
BEGIN IF not c_emp %ISOPEN THENOPEN c_emp;END IF;--抓取游标中的第一条记录FETCH c_emp into v_empno, v_ename;--对游标进行循环操作: 判断游标中是否有下一条记录WHILE c_emp %FOUND LOOPDBMS_OUTPUT.put_line(v_empno || '-' || v_ename);FETCH c_emp into v_empno, v_ename;END LOOP; --游标使用完毕后关闭游标CLOSE c_emp;
END;
--有参数无返回值游标 例子
DECLARECURSOR c4(dept_id NUMBER, j_id VARCHAR2) --1、声明游标,有参数没有返回值ISSELECT first_name f_name, hire_date FROM employeesWHERE department_id = dept_id AND job_id = j_id;--基于游标定义记录变量,比声明记录类型变量要方便,不容易出错v_emp_record c4%ROWTYPE;
BEGINOPEN c4(90, 'AD_VP');             --2、打开游标,传递参数值LOOPFETCH c4 INTO v_emp_record;    --3、提取游标fetch intoIF c4%FOUND THENDBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是'||v_emp_record.hire_date);ELSEDBMS_OUTPUT.PUT_LINE('已经处理完结果集了');EXIT;END IF;END LOOP;CLOSE c4;                         --4、关闭游标
END;

显示游标的属性

用户可以通过检查游标属性来确定游标的当前状态:

%FOUND:FETCH语句成功返回时,则%FOUND的值为TRUE。

%NOTFOUND:FETCH语句未能提取行时,则%NOTFOUND的值为TRUE。

%ISOPEN:如果游标已经打开,则返回TRUE,否则返回FALSE。

%ROWCOUNT:返回目前为止游标提取的行数,%ROWCOUNT为数值型属性。在第一次获取之前,%ROWCOUNT为0。当FETCH语句返回一行时,则该数加1。

遍历显示游标

DECLARECURSOR c_emp IS SELECT empno,ename FROM emp;v_empno emp.empno%TYPE;v_ename emp.ename%TYPE;
BEGIN IF not c_emp %isopen THENOPEN c_emp;END IF;--对游标进行循环操作: 判断游标中是否有下一条记录LOOPFETCH c_emp INTO v_empno, v_ename;EXIT WHEN c_emp %notfound;DBMS_OUTPUT.put_line(v_empno || '-' || v_ename);END LOOP;/* 或者FETCH c_emp into v_empno, v_ename;WHILE c_emp %FOUND LOOPDBMS_OUTPUT.put_line(v_empno || '-' || v_ename);FETCH c_emp into v_empno, v_ename;END LOOP; */--游标使用完毕后关闭游标CLOSE c_emp;
END;

显示游标的FOR循环

为了简化游标的应用,Oracle提供了游标的for循环语句可以隐式地 OPEN,FETCH,CLOSE 游标以及循环处理结果集。

DECLARE CURSOR c_emp IS SELECT empno, ename FROM emp;
BEGIN  --隐式地 OPEN,FETCH,CLOSE 游标以及循环处理结果集FOR emp IN c_emp LOOPDBMS_OUTPUT.put_line(emp.empno || '-' || emp.ename);END LOOP;
END;

或者可以在游标 FOR 循环语句中使用子查询

BEGINFOR c1_rec IN (SELECT department_name, location_id FROM departments) LOOP DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);END LOOP;
END;

接收显式游标数据的数据类型(普通变量、记录变量、集合变量)

1、使用普通变量接收游标数据

declarev_cnt number :=20;cursor emp_cursor is select ename,job,sal from emp where deptno=v_cnt;vname emp.ename%type;vsal emp.sal%type;vjob emp.job%type;
beginopen emp_cursor;loopfetch emp_cursor into vname, vjob, vsal;    --使用普通变量接收游标数据exit when emp_cursor%notfound;dbms_output.put_line('姓名' || vname || '岗顶' || vjob || '工资' || vsal);end loop;close emp_cursor;
end;

2、使用PL/SQL记录变量接收游标数据:简化单行数据处理

declarev_cnt number :=5;cursor ecur is select ename,sal from emp order by sal desc; --游标erec ecur%rowtype;           --定义声明一个行级的PL/SQL记录变量erec
beginopen ecur;loopfetch ecur into erec;    --使用PL/SQL记录变量接收游标数据exit when ecur%notfound or ecur%rowcount > v_cnt;dbms_output.put_line('姓名' || erec.ename ||  '工资' || erec.sal);end loop;close ecur;
end;

3、使用PL/SQL集合变量接收游标数据,简化多行多列数据处理

declarev_cnt number :=5;cursor ec is select ename,sal from emp where lower(job)=lower(v_cnt); --游标type eetype is table of ec%rowtype index by binary_intefer; --定义一个复合数据类型PL/SQL表变量eetypeet eetype; --声明etypei int;
beginopen ec;loopi:= ec%rowcount + 1;fetch ec into et(i);    --使用PL/SQL集合变量接收游标数据exit when ec%notfound;dbms_output.put_line('姓名' || et(i).ename ||  '工资' || et(i).sal);end loop;close ec;
end;

通过游标更新、删除表的数据

说明:必须要带for update子句。
语法:cursor cursor_name(parameter_name datatype) is select_statement for update [of column_reference] [nowait]
其中,for update用于在游标结果集加共享锁。
当select语句引用多张表示,使用of子句可以确定哪些表要加锁,没有则select语句所引用的全部表加上锁。
nowait用于指定不等待锁,当其他会话已经锁表之后,默认是当前会话一直等待释放,但指定了NOWAIT后,
如果表已经被其它会话加锁,则抛出异常并退出当前块。
注意,为了更新或删除当前游标行数据,必须在update或delete语句中引用where current of子句。
例子:
cursor c_name is select emp.sal,dept.deptno from emp,dept where emp.deptno=dept.deptno for update;–全部加共享锁
cursor c_name is select emp.sal,dept.deptno from emp,dept where emp.deptno=dept.deptno for update of emp.deptno;–只在emp表加共享锁
cursor c_name is select sal from emp for update nowait;

declare
cursor emp_cursor is select ename,sal,deptno from emp for update;–默认所有表均加上共享锁。
dno int:=1001;
begin
for emp_record in emp_cursor loop
if emp_record.deptno=dno then
update emp set sal=sal*1.1 where current of emp_cursor; --更新操作
delete from emp where current of emp_cursor; --删除操作
end if;
end loop;
end;

显式游标在开发中不多见的应用

1、通过游标更新、删除表的数据对于多表的情况(使用for子句在特定表上加共享锁)

declarecursor emp_cursor is select a.dname,b.ename from dept a join emp b on a.deprno=b.deptno;name varchar2(20):='sales';
beginfor emp_record in emp_cursor loopif emp_record.dname=name thendelete from emp where current of emp_cursor;end if;end loop;
end;

2、使用fetch…bulk collect批量提取所有数据

declarev_name varchar2(20):='clerk';cursor ec is select * from emp where job=v_name;type etype is table of emp%rowtype; --定义一个复合数据类型嵌套表etype(就看成定义了一个集合)et etype;
beginopen ec;fetch ec bulk collect into et;    --把游标里的数据都放入到集合中close ec;for i in 1..et.count loopdbms_output.put_line('姓名' || et(i).ename || '工资' || et(i).sal);end loop;
end;

3、使用fetch…bulk collect批量提取 + limit子句限制提取行数的应用

declarev_cnt number:=4;cursor ec is select * from emp;type emp_array_type is varray(5) of emp%rowtype; --定义一个复合数据类型varray数组(就看成定义了一个集合)ea emp_array_type;
beginopen ec;loopfetch ec bulk collect into ea limit v_cnt;for i in 1..ea.count loopdbms_output.put_line('姓名' || et(i).ename || '工资' || et(i).sal); --结果只会输出4行end loop;exit when ec%notfound;end loop;close ec;
end;

4、游标中保存着游标的应用

declarev_dno number:=5010;cursor dept_cursor(no number) is select a.dname,cursor(select * from emp where deptno=a.deptno) from dept a where a.deptno=no;type ref_cursor_type is ref cursor;ec ref_cursor_type;er emp%rowtype;vdname dept.dname%type;
beginopen dept_cursor(v_dno);loopfetch dept_cursor into vdname,ec;exit when dept_cursor%notfound;dbms_output.put_line('部门' || vdname);loopfetch ec into er;exit when ec%notfound;dbms_output.put_line('雇员' || er.ename || '岗位' || er.job); --一个部门有多名员工end loop;end loop;close dept_cursor;
end;

隐式游标

显式游标主要是用于对查询语句的处理,尤其是在查询结果为多条记录的情况下

而对于非查询语句,如修改、删除操作,则由ORACLE 系统自动地为这些操作设置游标并创建其工作区,隐式游标的名字为SQL,这是由ORACLE 系统定义的。

对于隐式游标的操作,如定义、打开、取值及关闭操作,都由ORACLE 系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据

如前所述,DML操作和单行SELECT语句会使用隐式游标,它们是:
插入操作:INSERT。
更新操作:UPDATE。
删除操作:DELETE。
单行查询操作:SELECT … INTO …。

DECLAREv_rows NUMBER;
BEGIN--更新数据UPDATE employees SET salary = 30000WHERE department_id = 90 AND job_id = 'AD_VP';--获取默认游标的属性值v_rows := SQL%ROWCOUNT;DBMS_OUTPUT.PUT_LINE('更新了'||v_rows||'个雇员的工资');--删除指定雇员;如果部门中没有雇员,则删除部门DELETE FROM employees WHERE department_id = v_deptno;IF SQL%NOTFOUND THENDELETE FROM departments WHERE department_id=v_deptno;END IF;
END;

当系统使用一个隐式游标时,也可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程

隐式游标的属性

SQL%ROWCOUNT:代表DML语句成功执行的数据行数
SQL%FOUND:值为TRUE代表插入、删除、更新或单行查询操作成功
SQL%NOTFOUND:与SQL%FOUND属性返回值相反
SQL%ISOPEN:DML执行过程中为真,结束后为假

提示一下:因为隐式游标默认打开游标,但是如果调用%ISOPEN 却返回FALSE

动态游标的使用

在变量声明部分定义的游标是静态的,不能在程序运行过程中修改。虽然可以通过参数传递来取得不同的数据,但还是有很大的局限性。通过采用动态游标,可以在程序运行阶段随时生成一个查询语句作为游标。要使用动态游标需要先定义一个游标类型,然后声明一个游标变量,游标对应的查询语句可以在程序的执行过程中动态地说明。

动态游标用于处理运行时动态执行的SQL查询的结果集
定义游标类型的语句如下:TYPE 游标类型名 IS REF CURSOR [return 返回值类型]
声明游标变量的语句如下:游标变量名 游标类型名;
在可执行部分可以如下形式打开一个动态游标:OPEN 游标变量名 FOR 查询语句字符串;

DECLARETYPE cur_type IS REF CURSOR;   cur cur_type;   rec scott.emp%ROWTYPE;   str VARCHAR2(50);   letter CAHR := 'A';
BEGINLOOP           str := 'SELECT ename FROM emp WHERE ename LIKE ''%'||letter||'%''';   OPEN cur FOR str;   DBMS_OUTPUT.put_line('包含字母'||letter||'的名字:');   LOOP   FETCH cur INTO rec.ename;   EXIT WHEN cur%NOTFOUND;   DBMS_OUTPUT.put_line(rec.ename);   END LOOP;   EXIT WHEN letter = 'Z';   Letter := CHR(ASCII(letter) + 1);   END LOOP;
END;
DECLARE--强类型的游标类型(有返回值)TYPE strong_cursor_type IS REF CURSOR RETURN emp%ROWTYPE;--弱类型的游标类型(无返回值)TYPE weak_cursor_type IS REF CURSOR;--变量定义strong_cursor strong_cursor_type;weak_cursor weak_cursor_type;v_emp emp%ROWTYPE;
BEGINOPEN strong_cursor FOR SELECT * FROM emp;LOOPFETCH strong_cursor INTO v_emp;EXIT WHEN strong_cursor%notfound;DBMS_OUTPUT.put_line(v_emp.empno || '-' || v_emp.ename);END LOOP;CLOSE strong_cursor;OPEN weak_cursor FOR '&sql';LOOPFETCH weak_cursor INTO v_emp;EXIT WHEN weak_cursor%notfound;DBMS_OUTPUT.put_line(v_emp.empno || '-' || v_emp.ename);END LOOP;CLOSE weak_cursor;
END;

静态游标和动态游标的区别

  • 静态游标是静态定义,REF游标是动态关联
  • 静态游标只能处理静态的查询语言,动态游标可以处理动态查询语句的结果集。
  • 动态游标能作为参数进行传递,而静态游标是不能的。

更新或删除当前游标数据

游标查询语句中尽量使用FOR UPDATE选项,以便在打开游标时锁定游标结果集合在表中对应数据行的所有列和部分列。

如果另一个会话已对活动集中的行加了锁,那么SELECT FOR UPDATE操作一直等待到其它的会话释放这些锁后才继续自己的操作;对于这种情况,当加上NOWAIT子句时,如果这些行真的被另一个会话锁定,则OPEN立即返回并给出: ORA-0054 :resource busy and acquire with nowait

DECLARE V_deptno employees.department_id%TYPE := &p_deptno;CURSOR emp_cursor IS SELECT employees.employee_id, employees.salary FROM employees WHERE employees.department_id=v_deptnoFOR UPDATE NOWAIT;                    --1、for update
BEGINFOR emp_record IN emp_cursor LOOPIF emp_record.salary < 1500 THENUPDATE employees SET salary=1500WHERE CURRENT OF emp_cursor; --2、WHERE CURRENT OF cursor_name子句END IF;END LOOP;
END

游标(概念、优点、分类、静态游标的使用(显示游标(显示游标的属性、遍历显示游标、显示游标的FOR循环)、隐式游标(隐式游标的属性))、动态游标的使用、静态游标和动态游标的区别、更新或删除当前游标数据相关推荐

  1. sqlserver游标概念与实例

    我们先不讲游标的什么概念,步骤及语法,先来看一个例子:        表一 OriginSalary                                                   ...

  2. 【转】sqlserver游标概念与实例全面解说

    引言  我们先不讲游标的什么概念,步骤及语法,先来看一个例子:       表一 OriginSalary                                                ...

  3. sqlserver游标概念与实例全面解说

    引言  我们先不讲游标的什么概念,步骤及语法,先来看一个例子:       表一 OriginSalary                                                ...

  4. 什么是mysql的游标_MySQL游标概念是什么 MySQL游标概念与用法介绍

    本篇文章小编给大家分享一下MySQL游标概念与用法介绍,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看. 1.游标的概念(Cursor) 一条sql,对应N条资源,取出资源的接 ...

  5. mysql 创建游标报错,MySQL游标概念与用法详解

    本文实例讲述了mysql游标概念与用法.分享给大家供大家参考,具体如下: 1.游标的概念(cursor) 一条sql,对应n条资源,取出资源的接口,就是游标,沿着游标,可以一次取出1行.如果开发过安卓 ...

  6. mysql游标_MySQL游标概念与用法详解

    本文实例讲述了MySQL游标概念与用法.分享给大家供大家参考,具体如下: 1.游标的概念(Cursor) 一条sql,对应N条资源,取出资源的接口,就是游标,沿着游标,可以一次取出1行.如果开发过安卓 ...

  7. Pro*c使用滚动游标进行更新或删除游标行

    代码:xx.pc /* 功能:演示了Oracle滚动游标进行更新(或删除)操作 定义游标时注意事项: 1. DECLARE CURSOR语句必须是使用游标的第一条语句 2. 游标名称是一个标识符,而不 ...

  8. 【Java学习笔记】55:JDBC-MySQL基本使用,游标控制,CONCUR_UPDATABLE,更新/添加/删除

    配置了这么久终于可以学习JDBC了,在这之前,给刚刚的表多插入一些表项: mysql> USE newDB; Database changed mysql> INSERT INTO New ...

  9. 动态加载和静态加载及其编译步骤

    在类unix操作系统中,驱动加载方式一般分为:动态加载和静态加载,下面分别对其详细论述. 一.动态加载 动态加载是将驱动模块加载到内核中,而不能放入/lib/modules/下.     在2.4内核 ...

最新文章

  1. 父域与子域之的信任关系
  2. Ubuntu14.04安装NVIDIA驱动后之后无法进入图形界面
  3. 镗孔指令g76格式_11种孔加工固定循环指令+1个案例=完美解决孔加工问题
  4. VS2003 找不到IsProcessInJob()
  5. spring mvc中的@propertysource
  6. Cloudera Enterprise 试用版 6.3.1查看cloudrea的许可证---可用期限
  7. Ubuntu中update-alternatives命令(版本切换)
  8. 黑马程序员-Java基础-正则表达式
  9. 如何阅读一本书 pdf_如何快速阅读一本书?
  10. MySQL5.5加主键锁读问题【转】
  11. python6清空屏幕,python:文件的读取、创建、追加、删除、清空
  12. 八位二进制数码管显示multisim_显示屏基础知识(LED电子显示屏的维修资料(芯片))4...
  13. 【聚类分析】基于matlab GUI K-means聚类分析【含Matlab源码 791期】
  14. 科赫小雪花python实验报告_基于python绘制科赫雪花
  15. ansys 服务器系统,云服务器 ansys
  16. Cadence16.6 最新83号补丁下载-Hotfix_SPB16.60.083_wint_1of1.exe
  17. 打印机扫描显示服务器没有响应,打印机扫描一体机能够打印却不能扫描,提示缺少WIA的驱动程序...
  18. 苹果电脑自动重启怎么回事
  19. Java I/O---概述
  20. 全国计算机二级c语言怎么复习,全国计算机二级C语言知识点复习:基本知识

热门文章

  1. 视频剪辑工具,从指定秒数中随机抽帧,以图片格式保存
  2. 我们应该怎么写程序?
  3. Linux文件权限(密码、用户、组、文件权限)——————附带详细操作
  4. 鸿蒙系统第一部手机,第一家宣布接入鸿蒙系统的国产手机厂商!华为不孤单了...
  5. 2018苹果开发者账户忘记密保问题,导致协议无法更新解决方法(脱坑呀)
  6. python设计模式实现
  7. 2021年起重机司机(限门式起重机)考试试卷及起重机司机(限门式起重机)模拟考试
  8. 服务器正在停服维护请您稍后重试,11月5日中午魔兽服务器出现登录故障 网易发布紧急维护公告 回应强制停服质疑...
  9. 【关于通用六轴机械臂的动力学最小集参数】
  10. Web 2.0的八个核心模式与成功技巧