Oracle数据库数据编程SQL<3.3 PL/SQL 游标>

 游标(Cursor)是Oracle数据库中用于处理查询结果集的重要机制,它允许开发者逐行处理SQL语句返回的数据。

目录

一、游标基本概念

1. 游标定义

2. 游标分类 

二、静态游标

(一)显式游标

【一】不带参数,普通的显示游标

1. 显式游标使用步骤

2. 语法

3. 显式游标的四个属性

4. 注意事项

5. %notfound 和普通循环一起用

6. %found 和while循环一起用

7. 基本示例

【二】带参数的显示游标

1. 语法结构

2. 示例代码

3. 练习

(二)隐式游标

1.隐式游标的四个属性

2. 示例代码

二、动态游标

【动态游标注意事项】

【强类型游标和弱类型游标区别】

【动态游标类型定义】

(一)强类型游标

(二)弱类型游标(SYS_REFCURSOR)

(三)动态游标

三、游标变量与批量处理

1. 游标变量

2. 批量提取(BULK COLLECT)

3. 批量处理与FORALL

四、游标最佳实践

五、高级游标技术

1. 可更新游标 

2. 游标子查询

3. 游标表达式(12c+)


一、游标基本概念

1. 游标定义

游标是一个指向上下文区域的指针,用于处理SQL语句的执行结果。它提供了以下能力:

  • 逐行访问结果集

  • 跟踪当前处理的行

  • 对结果集进行修改或删除操作

2. 游标分类 

游标类型描述生命周期控制方式
静态隐式游标Oracle自动为每条SQL语句创建    单条SQL执行期间Oracle自动管理
显式游标开发者显式定义从OPEN到CLOSE开发者手动控制
动态REF游标动态游标,运行时确定灵活控制开发者控制

二、静态游标

(一)显式游标

显示的游标:在declare的部分用is显示了的游标

【一】不带参数,普通的显示游标

1. 显式游标使用步骤

(1)声明游标:定义游标及其关联的SELECT语句

(2)打开游标:执行查询,填充结果集

(3)提取数据:从结果集中获取行数据

(4)关闭游标:释放资源

2. 语法
-- 1. 声明游标
CURSOR cursor_name [(parameters)][RETURN return_type]IS select_statement;-- 2. 打开游标
OPEN cursor_name [(parameters)];-- 3. 提取数据
FETCH cursor_name INTO variable_list;-- 4. 关闭游标
CLOSE cursor_name;-- 5. 举例
declare
cursor cur_name is select语句;---声明一个显示游标
begin open cur_name;--打开游标fetch cur_name into 变量;--赋值变量,提取记录dbms_output.put_line()---打印close cur_name;--关闭游标
end;
/
3. 显式游标的四个属性
属性返回值描述说明

cursor_name%FOUND

布尔值

如果最近一次

FETCH返回行则为TRUE

游标的指针是否有值(有)对

(没有) 错

cursor_name%NOTFOUND

布尔值

如果最近一次

FETCH未返回行则为TRUE

游标的指针是否没值(有值)错,

(没值)对,理论上可以返回空

在open之后fetch之前可以返回空

cursor_name%ROWCOUNT

数值

到目前为止已提取的行数

游标的指针已经指了几行,返回数值,

但是要赋给变量才能显示

返回最近一次从游标读取的数据

cursor_name%ISOPEN

布尔值

如果游标已打开则为TRUE

判断是否打开游标(打开)对

(没有)错

4. 注意事项

首先声明一个游标,使用之前先打开游标,提取记录只能一行,可以多列

使用完游标要关闭游标,可以通过open打开游标继续使用

5. %notfound 和普通循环一起用
 open→loop fetch→exit when %notfound→打印→end loop→close【举例1】declarecursor cur_a is select * from emp;---声明一个显示游标v_emp emp%rowtype;---声明变量v1    varchar2(20);---声明变量
beginopen cur_a;--打开游标loop/*普通循环*/                                 fetch cur_a  into v_emp;/*赋值变量,抓取记录*/            exit when cur_a%notfound;/*和普通循环一起用*/                    dbms_output.put_line(v_emp.ename);                              end loop;/*结束循环*/                                                close cur_a;/*关闭游标*/                      end;
/-- LOOP循环语法 
declare 部分;
beginloop 要执行的语句;exit when 退出的条件;end loop;
end;
注意事项:进入循环不需要条件
6. %found 和while循环一起用
open→fetch→while %found loop→打印→fetch→end loop→close【举例】
declarecursor cur_a is select * from emp;v_emp emp%rowtype;
beginopen cur_a;fetch cur_a into v_emp;while cur_a%found loopdbms_output.put_line(v_emp.ename);fetch cur_a into v_emp;end loop;close cur_a;
end;
7. 基本示例
DECLARE-- 1. 声明游标CURSOR emp_cursor ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = 10;v_emp_id employees.employee_id%TYPE;v_name employees.last_name%TYPE;v_sal employees.salary%TYPE;
BEGIN-- 2. 打开游标OPEN emp_cursor;-- 3. 提取数据LOOPFETCH emp_cursor INTO v_emp_id, v_name, v_sal;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_id || ': ' || v_name || ', ' || v_sal);END LOOP;-- 4. 关闭游标CLOSE emp_cursor;
END;
/1、输出emp表工资前十名的员工姓名和薪资
declarecursor cur_1 isselect ename, salfrom (select ename, sal from emp order by sal desc)where rownum <= 10;v_n emp.ename%type;v_s emp.sal%type;
beginopen cur_1;loopfetch cur_1 into v_n, v_s;exit when cur_1%notfound;dbms_output.put_line('姓名:' || v_n || '薪资:' || v_s);end loop;close cur_1;
end;
/
-------------------
declarecursor cur_1 isselect ename, salfrom (select ename, sal from emp order by sal desc)where rownum <= 10;v_n emp.ename%type;v_s emp.sal%type;
beginopen cur_1;fetch cur_1 into v_n, v_s;while cur_1%found loopdbms_output.put_line('姓名:' || v_n || '薪资:' || v_s);fetch cur_1 into v_n, v_s;end loop;close cur_1;
end;
/

【二】带参数的显示游标

游标可以接受参数,使查询更加灵活:

1. 语法结构
CURSOR cursor_name (parameter1 datatype, parameter2 datatype, ...)IS select_statement;declarecursor cur_name(变量 类型) is select语句;---声明一个显示游标
begin open cur_name(变量);--打开游标fetch cur_name into 变量;--赋值变量,提取记录close cur_name;--关闭游标
end;
2. 示例代码
DECLARE-- 带参数的游标CURSOR emp_cursor (p_dept_id NUMBER, p_min_sal NUMBER) ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = p_dept_idAND salary >= p_min_sal;-- 记录类型变量v_emp_record emp_cursor%ROWTYPE;
BEGIN-- 打开游标并传入参数OPEN emp_cursor(10, 5000);LOOPFETCH emp_cursor INTO v_emp_record;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_record.employee_id || ': ' || v_emp_record.last_name || ', ' || v_emp_record.salary);END LOOP;CLOSE emp_cursor;
END;
/declarecursor cur_1(v1 number) is select sal from emp where empno = v1; --声明一个带参数的显示游标v_s emp.sal%type; --负责接收的变量
beginopen cur_1(&a); ---(7788)即为(v1 number)fetch cur_1 into v_s;dbms_output.put_line(v_s);close cur_1;
end;
3. 练习
【1】输出工作是MANAGER的姓名、工资、;工作是SALESMAN的姓名、佣金;
工作是CLERK的姓名、入职日期。
declarecursor cur_2(v1 varchar2) isselect * from emp where job = v1;v_emp emp%rowtype;
beginopen cur_2('MANAGER');---loopfetch cur_2into v_emp;exit when cur_2%notfound;dbms_output.put_line(v_emp.ename ||' '|| v_emp.sal);end loop;close cur_2;open cur_2('SALESMAN');loopfetch cur_2into v_emp;exit when cur_2%notfound;dbms_output.put_line(v_emp.ename ||' '|| v_emp.comm);end loop;close cur_2;open cur_2('CLERK');loopfetch cur_2into v_emp;exit when cur_2%notfound;dbms_output.put_line(v_emp.ename ||' '|| to_char(v_emp.hiredate,'yyyy-mm-dd'));end loop;close cur_2;
end;
/【2】输出工作是MANAGER的姓名、工作、;工作是SALESMAN的姓名、佣金;
工作是CLERK的姓名、入职日期。
declarecursor cur_xx(v_1 emp.job%type) isselect * from emp where job = v_1;v_emp emp%rowtype;
beginopen cur_xx('MANAGER');loopfetch cur_xxinto v_emp;exit when cur_xx%notfound;dbms_output.put_line('员工姓名:'||v_emp.ename ||'    '||'职位:'|| v_emp.job);end loop;close cur_xx;open cur_xx('SALESMAN');loopfetch cur_xxinto v_emp;exit when cur_xx%notfound;dbms_output.put_line('员工姓名:'||v_emp.ename ||'    '||'工资:'|| v_emp.sal);end loop;close cur_xx;open cur_xx('CLERK');loopfetch cur_xxinto v_emp;exit when cur_xx%notfound;dbms_output.put_line('员工姓名:'||v_emp.ename ||'    '||'入职日期:'||v_emp.hiredate);end loop;close cur_xx;
end;
/-----------------------------------------------------------------------------------------
输出名字中包含%的人
select * from emp where ename like '%'||v1||'%' or ename like'%'||v_2||'%'【3】打印名字中包含A的人数,包含E的平均工资,包含o的总工资
declarecursor cur_3(v1 varchar2) is---先让cur_3有了selecteselect count(sal), avg(sal), sum(sal)from empwhere ename like '%' || v1 || '%';----注意学习这种方法--声明一个带参数的显示游标cur_3v_2 number;v_3 number;v_4 number;
----------------添加负责接收的变量
beginopen cur_3('A');loopfetch cur_3---又从cur_3里提取值赋值给变量v_2,v_3,v_4into v_2, v_3, v_4;exit when cur_3%notfound;dbms_output.put_line(v_2);end loop;close cur_3;---------------open cur_3('E');loopfetch cur_3into v_2, v_3, v_4;exit when cur_3%notfound;dbms_output.put_line(v_3);end loop;close cur_3;----------------open cur_3('O');loopfetch cur_3into v_2, v_3, v_4;exit when cur_3%notfound;dbms_output.put_line(v_4);end loop;close cur_3;----------------
end;

(二)隐式游标

主要应用于增加删除更新数据,Oracle为每条DML语句自动创建隐式游标,当执行SQL语句的时候,这个游标是处理该语句的工作区域。在使用的时候要使用隐式游标的默认名称SQL。 

1.隐式游标的四个属性

属性返回描述说明
cursor_name%FOUND布尔值如果DML操作影响至少一行返回TRUE

游标的游标中是否有值,返回最近一次的结果,成功(对)否则(错)

cursor_name%NOTFOUND布尔值如果DML操作未影响任何行返回TRUE

游标的游标中是否有值,返回最近一次的结果,成功(错)

cursor_name%ROWCOUNT数值返回DML操作影响的行数

返回最近一次从游标中读取到的记录--数值类型

cursor_name%ISOPEN布尔值对隐式游标总是返回FALSE

判断是否打开游标。永远返回错

 补充:闪回不仅可以闪回删除前的数据,也可以返回之前某一时间点的数据

2. 示例代码

BEGIN-- 更新操作UPDATE employees SET salary = salary * 1.1 WHERE department_id = 10; -- 检查隐式游标属性IF SQL%FOUND THENDBMS_OUTPUT.PUT_LINE('更新了 ' || SQL%ROWCOUNT || ' 条记录');END IF;-- 删除操作DELETE FROM temp_employees WHERE employee_id = 9999;IF SQL%NOTFOUND THENDBMS_OUTPUT.PUT_LINE('未删除任何记录');END IF;
END;
----------------------------------------------------------------
----------------------------------------------------------------
/
begindelete from emp001 where deptno=10;--3--dbms_output.put_line('删除了'||sql%rowcount||'行');delete from emp001 where deptno=20;--5if sql%found thendbms_output.put_line('删除了'||sql%rowcount||'行') ;end if;end;
/
----------------------------------------------------------------
begin--dbms_output.put_line('删除了'||sql%rowcount||'行');delete from emp001 where deptno in (10,20);--5if sql%found thendbms_output.put_line('删除了'||sql%rowcount||'行') ;end if;
end;
/
----------------------------------------------------------------
----------------------------------------------------------------
declare
v_name csm_product.product_name%type;
begininsert into test_t values(1);if sql%found thendbms_output.put_line('收到影响的行数为:'||sql%rowcount);end if;rollback;
end;
----------------------------------------------------------------
----------------------------------------------------------------
declare
cursor v_cur is select * from test_t
beginif v_cur%isopen thendbms_output.put_line('游标已经打开');elsedbms_output.put_line('游标未打开');end if;open v_cur;if v_cur%isopen thendbms_output.put_line('游标已经打开');end if;close v_cur;insert into test_t valuse(1);if sql%found thendbms_output.put_line('执行成功,影响的行数:'||sql%rowcount)elsif sql%notfound thendbms_output.put_line('执行失败');end if;rollback;
end;

二、动态游标

【动态游标注意事项】

1、使用动态游标必须声明游标类型

2、只要列的格式相同,可以同时打开多表

【强类型游标和弱类型游标区别】

1、强类型游标有return,open时查询得到的结果要和return后的表的数据类型、结构、顺序一致。

2、没有return,open时查询的结果比较自由,fetch的时候into给的变量要和SQL查询的类型结构数量一致。

【动态游标类型定义】

TYPE cursor_type IS REF CURSOR [RETURN return_type];

(一)强类型游标

DECLARETYPE emp_cursor_type IS REF CURSOR RETURN employees%ROWTYPE;emp_cursor emp_cursor_type;v_emp employees%ROWTYPE;
BEGINOPEN emp_cursor FOR SELECT * FROM employees WHERE department_id = 20;LOOPFETCH emp_cursor INTO v_emp;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp.employee_id || ': ' || v_emp.last_name);END LOOP;CLOSE emp_cursor;
END;
/declaretype cur_name_ref is ref cursor return emp%rowtype; --emp可以自定义,只是声明了一个类型cur_1 cur_name_ref;v_emp    emp%rowtype;
begin
--------------------------------------------------------------------open cur_1 for select * from emp;-------------同时打开多表---------fetch cur_1into v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;
--------------------------------------------------------------------open cur_1 for select * from emp001;---------同时打开多表----------fetch cur_1into v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;
end;

(二)弱类型游标(SYS_REFCURSOR)

DECLAREemp_cursor SYS_REFCURSOR;v_emp_id employees.employee_id%TYPE;v_emp_name employees.last_name%TYPE;
BEGIN-- 打开第一个查询OPEN emp_cursor FOR SELECT employee_id, last_name FROM employees WHERE department_id = 10;DBMS_OUTPUT.PUT_LINE('部门10员工:');LOOPFETCH emp_cursor INTO v_emp_id, v_emp_name;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_id || ': ' || v_emp_name);END LOOP;CLOSE emp_cursor;-- 重用游标执行不同查询OPEN emp_cursor FOR SELECT department_id, department_name FROM departments;DBMS_OUTPUT.PUT_LINE('所有部门:');LOOPFETCH emp_cursor INTO v_emp_id, v_emp_name;  -- 重用变量EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_id || ': ' || v_emp_name);END LOOP;CLOSE emp_cursor;
END;
/declaretype cur_name_ref is ref cursor;---没有return,和强类型的区别就在于此cur_name cur_name_ref;v_emp    emp%rowtype;
beginopen cur_name for select * from emp;-------------同时打开多表---------------fetch cur_nameinto v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;---注意游标开一次,关一次,不然一直开着耗内存。open cur_name for select * from emp001;--------同时打开多表---------------fetch cur_nameinto v_emp;dbms_output.put_line(v_emp.deptno || v.emp.ename || v_emp.job);close cur_1;
end;【练习题】
1、输出工作是MANAGER的姓名、工资;工作是SALESMAN的姓名、佣金;
工作是CLERK的姓名、入职日期。
declaretype  cur_1_ref is ref cursor; ---没有returncur_1 cur_1_ref;v1    varchar2(20);v2    number;v3    date;
beginopen cur_1 forselect ename, sal from emp where job = 'MANAGER';loopfetch cur_1into v1, v2;exit when cur_1%notfound;dbms_output.put_line(v1 || v2);end loop;open cur_1 forselect ename, sal from emp where job = 'SALESMAN';loopfetch cur_1into v1, v2;exit when cur_1%notfound;dbms_output.put_line(v1 || v2);end loop;open cur_1 forselect ename, hiredate from emp where job = 'CLERK';loopfetch cur_1into v1, v3;exit when cur_1%notfound;dbms_output.put_line(v1 || v3);end loop;
end;
/--用弱类型游标,打印emp名字中包含A的人数,dept部门编号的平均数
--salgrade 第三等级的hisal
declaretype cur_name_ref is ref cursor;cur_gam cur_name_ref;v_1     number;
beginopen cur_gam forselect count(ename) from emp where ename like '%A%';----单列单行不用循环fetch cur_gaminto v_1;dbms_output.put_line('名字包含A的人数:' || v_1);close cur_gam;open cur_gam forselect avg(deptno) from dept;----单列单行不用循环fetch cur_gaminto v_1;dbms_output.put_line('部门编号的平均数:' || v_1);close cur_gam;open cur_gam forselect hisal from salgrade where grade = 3;----单列单行不用循环fetch cur_gaminto v_1;dbms_output.put_line('第三等级的hisal:' || v_1);close cur_gam;
end;
--------如果多行多列,加入循环的写法
declaretype cur_name_ref is ref cursor;cur_gam cur_name_ref;v_1 number;
beginopen cur_gam forselect count(ename) from emp where ename like '%A%';loopfetch cur_gaminto v_1;exit when cur_gam%notfound;dbms_output.put_line('名字包含A的人数:'||v_1);end loop;close cur_gam;
-----------------------open cur_gam forselect avg(deptno) from dept;loopfetch cur_gaminto v_1;exit when cur_gam%notfound;dbms_output.put_line('部门编号的平均数:'||v_1);end loop;close cur_gam;
-----------------------------open cur_gam forselect hisal from salgrade where grade=3;loopfetch cur_gaminto v_1;exit when cur_gam%notfound;dbms_output.put_line('第三等级的hisal:'||v_1);end loop;close cur_gam;
end;

(三)动态游标

【语法】
declarecur_name sys_refcursor;v1       number;v2       varchar2(20);
beginopen cur_name forselect empno, ename from emp where empno = 7788;fetch cur_nameinto v1, v2;dbms_output.put_line(v1 || v2);close cur_name;
--------------open cur_name forselect empno, ename from emp where deptno = 20;fetch cur_nameinto v1, v2;dbms_output.put_line(v1 || v2);close cur_name;
end;【练习题】
1、打印10部门的人员姓名和部门地址,打印20部门的工资和工资等级
declarecur_1 sys_refcursor;ve       varchar2(20);vc       varchar2(20);vs       number;vg       number;
beginopen cur_1 forselect e.ename,d.loc from emp e,dept d where e.deptno=d.deptno and d.deptno=10;loopfetch cur_1into ve, vc;exit when cur_1%notfound;dbms_output.put_line(ve ||'  '|| vc);end loop;open cur_1 forselect e.sal, s.grade from emp e,salgrade s where e.sal between s.losal and s.hisal and e.deptno=20;loopfetch cur_1into vs, vg;exit when cur_1%notfound;dbms_output.put_line(vs ||' '|| vg);end loop;close cur_1;
end;
/2、用动态游标里面的动态游标,打印emp名字中包含A的人数,dept部门编号的平均数,salgrade 第三等级的hisal
declarecur_2 sys_refcursor;v1    number;
beginopen cur_2 forselect count(ename) from emp where ename like '%A%';fetch cur_2into v1;dbms_output.put_line('名字包含A的人数:' || v1);close cur_2;
----------------------open cur_2 forselect avg(deptno) from dept;fetch cur_2into v1;dbms_output.put_line('部门编号的平均数:' || v1);close cur_2;
-----------------------open cur_2 forselect hisal from salgrade where grade = 3;fetch cur_2into v1;dbms_output.put_line('第三等级的hisal:' || v1);close cur_2;
end;
/

三、游标变量与批量处理

1. 游标变量

DECLARETYPE emp_cursor_type IS REF CURSOR;emp_cursor emp_cursor_type;PROCEDURE process_employees (p_cursor IN emp_cursor_type) ISv_emp employees%ROWTYPE;BEGINLOOPFETCH p_cursor INTO v_emp;EXIT WHEN p_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp.employee_id || ': ' || v_emp.last_name);END LOOP;END;
BEGINOPEN emp_cursor FOR SELECT * FROM employees WHERE department_id = 10;process_employees(emp_cursor);CLOSE emp_cursor;
END;
/

2. 批量提取(BULK COLLECT)

DECLARECURSOR emp_cursor ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = 10;-- 定义集合类型TYPE emp_id_array IS TABLE OF employees.employee_id%TYPE;TYPE name_array IS TABLE OF employees.last_name%TYPE;TYPE sal_array IS TABLE OF employees.salary%TYPE;v_ids emp_id_array;v_names name_array;v_sals sal_array;
BEGINOPEN emp_cursor;-- 批量提取数据FETCH emp_cursor BULK COLLECT INTO v_ids, v_names, v_sals;CLOSE emp_cursor;-- 处理批量数据FOR i IN 1..v_ids.COUNT LOOPDBMS_OUTPUT.PUT_LINE(v_ids(i) || ': ' || v_names(i) || ', ' || v_sals(i));END LOOP;
END;
/

3. 批量处理与FORALL

DECLARETYPE id_array IS TABLE OF employees.employee_id%TYPE;TYPE sal_array IS TABLE OF employees.salary%TYPE;v_ids id_array := id_array(101, 102, 103, 104, 105);v_new_sals sal_array;
BEGIN-- 批量查询SELECT salary BULK COLLECT INTO v_new_salsFROM employeesWHERE employee_id IN (SELECT COLUMN_VALUE FROM TABLE(v_ids));-- 批量更新FORALL i IN 1..v_ids.COUNTUPDATE employeesSET salary = v_new_sals(i) * 1.1WHERE employee_id = v_ids(i);COMMIT;DBMS_OUTPUT.PUT_LINE('成功更新 ' || SQL%ROWCOUNT || ' 条记录');
END;
/

四、游标最佳实践

1.  及时关闭游标:避免资源泄漏

BEGINOPEN emp_cursor;-- 处理数据
EXCEPTIONWHEN OTHERS THENIF emp_cursor%ISOPEN THENCLOSE emp_cursor;END IF;RAISE;
END;

2. 使用游标FOR循环:简化代码,自动处理打开/关闭

3. 批量操作:对大结果集使用BULK COLLECT和FORALL

4. 参数化游标:提高代码重用性

5. 限制返回行数:避免内存问题

FETCH emp_cursor BULK COLLECT INTO v_emps LIMIT 1000;

6. 使用合适的作用域:在包中定义常用游标

7. 性能监控:检查游标SQL的执行计划

五、高级游标技术

1. 可更新游标 

DECLARECURSOR emp_cursor ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = 10FOR UPDATE OF salary NOWAIT;v_raise_percent NUMBER := 0.1;
BEGINFOR emp_rec IN emp_cursor LOOPUPDATE employeesSET salary = salary * (1 + v_raise_percent)WHERE CURRENT OF emp_cursor;END LOOP;COMMIT;
END;
/

2. 游标子查询

DECLARECURSOR dept_cursor ISSELECT d.department_id, d.department_name,CURSOR(SELECT employee_id, last_nameFROM employeesWHERE department_id = d.department_id) AS emp_cursorFROM departments dWHERE d.location_id = 1700;v_emp_cursor SYS_REFCURSOR;v_emp_id employees.employee_id%TYPE;v_emp_name employees.last_name%TYPE;
BEGINFOR dept_rec IN dept_cursor LOOPDBMS_OUTPUT.PUT_LINE('部门: ' || dept_rec.department_name);v_emp_cursor := dept_rec.emp_cursor;LOOPFETCH v_emp_cursor INTO v_emp_id, v_emp_name;EXIT WHEN v_emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE('  ' || v_emp_id || ': ' || v_emp_name);END LOOP;CLOSE v_emp_cursor;END LOOP;
END;
/

3. 游标表达式(12c+)

DECLARECURSOR dept_cursor ISSELECT d.department_id, d.department_name,CURSOR(SELECT e.employee_id, e.last_nameFROM employees eWHERE e.department_id = d.department_id) AS emp_curFROM departments d;
BEGINFOR dept_rec IN dept_cursor LOOPDBMS_OUTPUT.PUT_LINE('部门: ' || dept_rec.department_name);FOR emp_rec IN dept_rec.emp_cur LOOPDBMS_OUTPUT.PUT_LINE('  员工: ' || emp_rec.last_name);END LOOP;END LOOP;
END;
/

游标是Oracle PL/SQL中处理结果集的核心机制,掌握各种游标技术可以显著提高数据库应用程序的效率和灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/74139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

逗万DareWorks|创意重构书写美学,引领新潮无界的文创革命

当传统文具陷入同质化泥潭时&#xff0c;逗万DareWorks品牌犹如一颗璀璨的明星&#xff0c;以其独特的创意理念和卓越的产品品质&#xff0c;迅速赢得了广大消费者的青睐。 逗万DareWorks隶属于东莞司贸文教赠品有限公司&#xff0c;后者深耕制笔行业45年&#xff0c;占地4.6万…

写Prompt的技巧和基本原则

一.基本原则 1.一定要描述清晰你需要大模型做的事情&#xff0c;不要模棱两可 2.告诉大模型需要它做什么&#xff0c;不需要做什么 改写前: 请帮我推荐一些电影 改写后: 请帮我推荐2025年新出的10部评分比较高的喜剧电影&#xff0c;不要问我个人喜好等其他问题&#xff…

【React】基于 React+Tailwind 的 EmojiPicker 选择器组件

1.背景 React 写一个 EmojiPicker 组件&#xff0c;基于 emoji-mart 组件二次封装。支持添加自定义背景 、Emoji 图标选择&#xff01;并在页面上展示&#xff01; 2.技术栈 emoji-mart/data 、emoji-mart : emoji 图标库、元数据 tailwindcss: 原子化 CSS 样式库 antd : 组…

Qt中绘制不规则控件

在Qt中绘制不规则控件可通过设置遮罩&#xff08;Mask&#xff09;实现。以下是详细步骤: ‌继承目标控件‌&#xff1a;如QPushButton或QWidget。‌重写resizeEvent‌&#xff1a;当控件大小变化时&#xff0c;更新遮罩形状。‌创建遮罩区域‌&#xff1a;使用QRegion或QPain…

Parallel_Scheduling_of_DAGs_under_Memory_Constraints论文阅读

内存约束下的 DAG 并行调度 点击阅读原文语雀链接更清晰 摘要 科学工作流通常被建模为任务的有向无环图&#xff08;DAG&#xff09;&#xff0c;这些任务代表计算模块及其依赖关系&#xff0c;依赖关系表现为任务生成的数据被其他任务使用。这种形式化方法允许使用运行时系统&…

探索MVC、MVP、MVVM和DDD架构在不同编程语言中的实现差异

MVC与MVP/MVVM/DDD架构对比&#xff0c;不同语言实现 MVC 分层架构设计概述 模型-视图-控制器&#xff08;Model-View-Controller&#xff0c;简称 MVC&#xff09;是一种经典软件架构设计&#xff0c;通过分层解耦&#xff0c;使得系统结构清晰和易于维护&#xff0c;具有良…

一文读懂 UML:基础概念与体系框架

UML 图是一种标准化的建模语言&#xff0c;在软件开发和系统设计等领域有着广泛的应用。以下是对 UML 图各类图的详细介绍&#xff1a; 1.用例图 定义&#xff1a;用例图是从用户角度描述系统功能的模型图&#xff0c;展现了系统的参与者与用例之间的关系。作用&#xff1a;帮…

Spring 及 Spring Boot 条件化注解(15个)完整列表及示例

Spring 及 Spring Boot 条件化注解完整列表及示例 1. 所有条件化注解列表 Spring 和 Spring Boot 提供了以下条件化注解&#xff08;共 15 个&#xff09;&#xff0c;用于在配置类或方法上实现条件化注册 Bean 或配置&#xff1a; 注解名称作用来源框架Conditional自定义条件…

【Kafka】深入探讨 Kafka 如何保证一致性

文章目录 Kafka 基本概念回顾​副本角色​ 数据写入一致性​同步副本&#xff08;ISR&#xff09;集合​数据读取一致性​故障处理与一致性恢复​总结​ 在分布式系统领域&#xff0c;数据一致性是至关重要的一环。作为一款高性能的分布式消息队列系统&#xff0c;Kafka 在设计…

从入门到精通:SQL注入防御与攻防实战——红队如何突破,蓝队如何应对!

引言&#xff1a;为什么SQL注入攻击依然如此强大&#xff1f; SQL注入&#xff08;SQL Injection&#xff09;是最古老且最常见的Web应用漏洞之一。尽管很多公司和组织都已经采取了WAF、防火墙、数据库隔离等防护措施&#xff0c;但SQL注入依然在许多情况下能够突破防线&#…

【算法day27】有效的数独——请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

36. 有效的数独 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例…

leetcode 2360. 图中的最长环 困难

给你一个 n 个节点的 有向图 &#xff0c;节点编号为 0 到 n - 1 &#xff0c;其中每个节点 至多 有一条出边。 图用一个大小为 n 下标从 0 开始的数组 edges 表示&#xff0c;节点 i 到节点 edges[i] 之间有一条有向边。如果节点 i 没有出边&#xff0c;那么 edges[i] -1 。…

PySpur: AI 智能体可视化开发平台

GitHub&#xff1a;https://github.com/PySpur-Dev/pyspur 更多AI开源软件&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI PySpur是一个开源的轻量级可视化AI智能体工作流构建器&#xff0c;旨在简化AI系统的开发流程。通过拖拽式界面&#xff0c;用户…

vcpkg安装及使用教程,以安装matio库解析mat文件为例

vcpkg安装及使用教程,以安装matio库解析mat文件为例 1. vcpkg安装2 安装matio三方库3 将三方库集成到VS中3.1 全局集成3.2 集成到特定工程4 结语Vcpkg 是微软开发的一款开源的 C/C++ 包管理工具,旨在简化 C/C++ 项目依赖库的安装和管理。它支持跨平台(Windows、Linux、macO…

LLM架构解析:NLP基础(第一部分)—— 模型、核心技术与发展历程全解析

本专栏深入探究从循环神经网络&#xff08;RNN&#xff09;到Transformer等自然语言处理&#xff08;NLP&#xff09;模型的架构&#xff0c;以及基于这些模型构建的应用程序。 本系列文章内容&#xff1a; NLP自然语言处理基础&#xff08;本文&#xff09;词嵌入&#xff0…

【Rtklib入门指南】2. 使用RTKLIB GUI进行观测数据分析

数据准备 下载2025年1月1日的香港CORS站数据和观测星历&#xff0c;详情参照如下博客&#xff1a; 使用GAMP_GOOD进行hk数据下载教程-CSDN博客 分析工具 RTKLIB 2.4.3 demo5&#xff08;也可以选用RTKLIB2.4.2&#xff0c;但不建议使用RTKLIB2.4.3&#xff09; 分析流程 …

suse15 sp1使用华为云软件源yum源zypper源

登录suse15终端&#xff0c; cd /etc/zypp/repos.d/进入目录后执行以下命令&#xff1a; zypper ar -fcg https://mirrors.huaweicloud.com/opensuse/distribution/leap/15.1/repo/oss HuaWeiCloud:15.1:OSS zypper ar -fcg https://mirrors.huaweicloud.com/opensuse/distribu…

首屏加载时间优化解决

&#x1f916; 作者简介&#xff1a;水煮白菜王&#xff08;juejin/csdn同名&#xff09; &#xff0c;一位前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 高德AMap专栏 &#xff0c;记录一下平时学习在博客写作中记录&#xff0c;总结出的一些开发技巧✍。 感…

Sentinel[超详细讲解]-1

定义一系列 规则 &#x1f47a;&#xff0c;对资源进行 保护 &#x1f47a;&#xff0c; 如果违反的了规则&#xff0c;则抛出异常&#xff0c;看是否有fallback兜底处理&#xff0c;如果没有则直接返回异常信息&#x1f60e; 1. 快速入门 1.1 引入 Sentinel 依赖 <depend…

02-Docker 使用

docker:快速构建、运行、管理应用的工具,可以帮助我们下载应用镜像,创建并运行镜像的容器,从而快速部署应用 1、部署mysql 先停掉虚拟机中的MySQL,确保你的虚拟机已经安装Docker,且网络开通的情况下,执行下面命令即可安装MySQL(注意:若服务器上已经有mysql 占用了330…