1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【Oracle】PL/SQL 显式游标 隐式游标 动态游标

【Oracle】PL/SQL 显式游标 隐式游标 动态游标

时间:2018-07-29 23:01:17

相关推荐

【Oracle】PL/SQL 显式游标 隐式游标 动态游标

在PL/SQL块中执行SELECT、INSERT、DELETE和UPDATE语句时,Oracle会在内存中为其分配上下文区(ContextArea),即缓冲区。游标是指向该区的一个指针,或是命名一个工作区(WorkArea),或是一种结构化数据类型。

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

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

处理显式游标

例:

[sql]view plaincopy print? DECLARECURSORc4(dept_idNUMBER,j_idVARCHAR2)--1、声明游标,有参数没有返回值ISSELECTfirst_namef_name,hire_dateFROMemployeesWHEREdepartment_id=dept_idANDjob_id=j_id;--基于游标定义记录变量,比声明记录类型变量要方便,不容易出错v_emp_recordc4%ROWTYPE;BEGINOPENc4(90,'AD_VP');--2、打开游标,传递参数值LOOPFETCHc4INTOv_emp_record;--3、提取游标fetchintoIFc4%FOUNDTHENDBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是'||v_emp_record.hire_date);ELSEDBMS_OUTPUT.PUT_LINE('已经处理完结果集了');EXIT;ENDIF;ENDLOOP;CLOSEc4;--4、关闭游标END;

退出LOOP或者用:

EXITWHENc4%NOTFOUND;

游标属性:

Cursor_name%FOUND布尔型属性,当最近一次提取游标操作FETCH成功则为TRUE,否则为FALSE;

Cursor_name%NOTFOUND布尔型属性,与%FOUND相反;——注意区别于DO_DATA_FOUND(select into抛出异常)

Cursor_name%ISOPEN布尔型属性,当游标已打开时返回TRUE;

Cursor_name%ROWCOUNT数字型属性,返回已从游标中读取的记录数。

游标的for循环

PL/SQL语言提供了游标FOR循环语句,自动执行游标的OPEN、FETCH、CLOSE语句和循环语句的功能;

当进入循环时,游标FOR循环语句自动打开游标,并提取第一行游标数据;当程序处理完当前所提取的数据而进入下一次循环时,游标FOR循环语句自动提取下一行数据供程序处理;当提取完结果集合中的所有数据行后结束循环,并自动关闭游标。

格式:

FORindex_variableINcursor_name[(value[,value]…)]LOOP

--游标数据处理代码

ENDLOOP;

其中:

index_variable为游标FOR循环语句隐含声明的索引变量,该变量为记录变量,其结构与游标查询语句返回的结构集合的结构相同。在程序中可以通过引用该索引记录变量元素来读取所提取的游标数据,index_variable中各元素的名称与游标查询语句选择列表中所制定的列名相同。如果在游标查询语句的选择列表中存在计算列,则必须为这些计算列指定别名后才能通过游标FOR循环语句中的索引变量来访问这些列数据。

例:

[sql]view plaincopy print? DECLARECURSORc_cursor(dept_noNUMBERDEFAULT10)ISSELECTdepartment_name,location_idFROMdepartmentsWHEREdepartment_id<=dept_no;BEGIN--当dept_no参数值为30FORc1_recINc_cursor(30)LOOPDBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);ENDLOOP;--使用默认的dept_no参数值10FORc1_recINc_cursorLOOPDBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);ENDLOOP;END;

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

[sql]view plaincopy print? BEGINFORc1_recIN(SELECTdepartment_name,location_idFROMdepartments)LOOPDBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);ENDLOOP;END;

处理隐式游标

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

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

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

格式调用为:SQL%

[sql]view plaincopy print? DECLAREv_rowsNUMBER;BEGIN--更新数据UPDATEemployeesSETsalary=30000WHEREdepartment_id=90ANDjob_id='AD_VP';--获取默认游标的属性值v_rows:=SQL%ROWCOUNT;DBMS_OUTPUT.PUT_LINE('更新了'||v_rows||'个雇员的工资');--删除指定雇员;如果部门中没有雇员,则删除部门DELETEFROMemployeesWHEREdepartment_id=v_deptno;IFSQL%NOTFOUNDTHENDELETEFROMdepartmentsWHEREdepartment_id=v_deptno;ENDIF;END;

更新或删除当前游标数据

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

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

ORA-0054:resourcebusyandacquirewithnowaitspecified.

[sql]view plaincopy print? DECLAREV_deptnoemployees.department_id%TYPE:=&p_deptno;CURSORemp_cursorISSELECTemployees.employee_id,employees.salaryFROMemployeesWHEREemployees.department_id=v_deptnoFORUPDATENOWAIT;--1、forupdateBEGINFORemp_recordINemp_cursorLOOPIFemp_record.salary<1500THENUPDATEemployeesSETsalary=1500WHERECURRENTOFemp_cursor;--2、WHERECURRENTOFcursor_name子句ENDIF;ENDLOOP;END;

动态游标

与游标一样,动态游标(游标变量)也是一个指向多行查询结果集合中当前数据行的指针。但与游标不同的是,游标变量是动态的,而游标是静态的。

游标只能与指定的查询相连,即固定指向一个查询的内存处理区域,而游标变量则可与不同的查询语句相连,它可以指向不同查询语句的内存处理区域(但不能同时指向多个内存处理区域,在某一时刻只能与一个查询语句相连),只要这些查询语句的返回类型兼容即可。

[sql]view plaincopy print? DECLARE--定义一个游标数据类型TYPEemp_cursor_typeISREFCURSOR;--声明一个游标变量c1EMP_CURSOR_TYPE;--声明两个记录变量v_emp_recordemployees%ROWTYPE;v_reg_recordregions%ROWTYPE;BEGINOPENc1FORSELECT*FROMemployeesWHEREdepartment_id=20;LOOPFETCHc1INTOv_emp_record;EXITWHENc1%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name||'的雇佣日期是'||v_emp_record.hire_date);ENDLOOP;--将同一个游标变量对应到另一个SELECT语句OPENc1FORSELECT*FROMregionsWHEREregion_idIN(1,2);LOOPFETCHc1INTOv_reg_record;EXITWHENc1%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_reg_record.region_id||'表示'||v_reg_record.region_name);ENDLOOP;CLOSEc1;END;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。