当前位置: 首页 > news >正文

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中处理结果集的核心机制,掌握各种游标技术可以显著提高数据库应用程序的效率和灵活性。

相关文章:

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

游标(Cursor)是Oracle数据库中用于处理查询结果集的重要机制&#xff0c;它允许开发者逐行处理SQL语句返回的数据。 目录 一、游标基本概念 1. 游标定义 2. 游标分类 二、静态游标 &#xff08;一&#xff09;显式游标 【一】不带参数&#xff0c;普通的显示游标 1. 显式…...

OLLAMA 未授权访问-漏洞挖掘

1.漏洞描述 Ollama存在未授权访问漏洞。由于Ollama默认未设置身份验证和访问控制功能&#xff0c;未经授权的攻击者可在远程条件下调用Ollama服务接口&#xff0c;执行包括但不限于敏感模型资产窃取、虚假信息投喂、模型计算资源滥用和拒绝服务、系统配置篡改和扩大利用等恶意…...

多线程—线程安全集合类与死锁

上篇文章&#xff1a; 多线程—JUChttps://blog.csdn.net/sniper_fandc/article/details/146713322?fromshareblogdetail&sharetypeblogdetail&sharerId146713322&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 线程安全的集合类 …...

【鸿蒙5.0】鸿蒙登录界面 web嵌入(隐私页面加载)

在鸿蒙应用中嵌入 Web 页面并加载隐私页面&#xff0c;可借助 WebView 组件来实现。以下是一个完整示例&#xff0c;展示如何在鸿蒙 ArkTS 里嵌入 Web 页面并加载隐私政策页面。 在 HarmonyOS 应用开发中&#xff0c;如果你希望嵌入一个网页&#xff0c;并且特别关注隐私页面加…...

C++轻量HeaderOnly的JSON库

文章目录 1 nlohmann/json库说明2 nlohmann/json特点3 nlohmann/json库的使用方法3.1 引入头文件3.2 解析JSON字符串3.3 访问JSON数据3.4 生成JSON对象3.5 修改JSON数据3.6 将JSON写入文件3.7 遍历JSON对象 4 代码示例4.1 定义JSON数值类型4.2 从STL容器转换到json4.3 string序…...

打包python文件生成exe

下载PyInstaller 官网 pip install pyinstaller验证是否安装成功 pyinstaller --version打包 pyinstaller "C:\Documents and Settings\project\myscript.py"会生成.spec,build,dist三项&#xff0c;其中build,dist为文件夹&#xff0c;dist是最后的可执行文件&a…...

Nginx — Nginx安装证书模块(配置HTTPS和TCPS)

一、安装和编译证书模块 [rootmaster nginx]# wget https://nginx.org/download/nginx-1.25.3.tar.gz [rootmaster nginx]# tar -zxvf nginx-1.25.3.tar.gz [rootmaster nginx]# cd nginx-1.25.3 [rootmaster nginx]# ./configure --prefix/usr/local/nginx --with-http_stub_…...

《Mycat核心技术》第21章:高可用负载均衡集群的实现(HAProxy + Keepalived + Mycat)

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章汇总&#xff1a;https://binghe.gitcode.host/md/all/all.html 星球项目地址&#xff1a;https://binghe.gitcode.host/md/zsxq/introduce.html 沉淀&#xff0c…...

Dynamic WallPaper-壁纸动态-Mac电脑-4K超高清

Dynamic WallPaper-壁纸动态-Mac电脑-4K超高清 文章目录 Dynamic WallPaper-壁纸动态-Mac电脑-4K超高清一、介绍二、效果三、下载 一、介绍 Dynamic Wallpaper for mac版&#xff0c;是一款4K超高清动态壁纸软件&#xff0c;告别单调的静态壁纸&#xff0c;拥抱活泼的动态壁纸…...

MySQL8.4 NDB Cluster 集群配置安装

文章目录 前置条件安装步骤环境准备下载 安装 RPM 包安装 NDB 组件与常见错误配置节点启用节点配置启动 MySQL 集群验证集群状态 关于 ndb_mgm集群管理备份与恢复集群配置管理日志相关 MySQL NDB Cluster 是一个分布式数据库解决方案&#xff0c;提供高可用性、数据分片和自动故…...

多线程开发中List的使用

由于ArrayList在多线程高并发情况下是不安全的&#xff0c;因此要慎用&#xff0c;那么此时如果涉及到集合操作&#xff0c;应该怎么选&#xff1a; 方案一&#xff1a;Vector: 特点&#xff1a;通过给所有方法都用 synchronized 修饰从而保证线程安全&#xff0c; 缺点&…...

Html 页面图标的展示列表

Html 页面中经常需要使用网页图标&#xff0c;这些图标的样式和名称都不容易记住。常用的网页图标展示页面链接记录如下&#xff1a; Material Design Icons 图标库 - FontAwesome 字体图标中文Icon...

Vue实现动态路由的后端控制

在传统开发后台管理系统时&#xff0c;都会涉及权限控制这一功能需求 即&#xff1a;根据不同登录的角色账号来使用该账号拥有的功能&#xff0c;也就是说系统左边的菜单栏不是固定不变的。 首先是基础路由配置带有component的。 const allRoutes [// 基础路由{path: /,name…...

​AI训练中的专有名词大白话版

​AI训练中的专有名词大白话版 ​1. 数据集&#xff08;Dataset&#xff09;​ &#x1f449; ​人话&#xff1a;AI的“练习题题库”&#xff0c;包含一堆带答案的题目&#xff08;比如猫狗照片标签&#xff09;。 &#x1f539; ​例子&#xff1a; 训练集&#xff08;练习…...

kafka 与 RocketMQ对比

问题 1: 为什么使用消息队列?服务搭建KafkaRocketMQ编写 docker-compose.yml运行docker compose修改配置文件(解决网络问题)创建一个 topic运行skd尝试发送与接收功能 压力测试:Kafkabatch-size(批量大小)分区数:发送数据(MB/s)消费-线程数(15 分区) RocketMQ生产生产者数量批…...

instnatid模型加载器放在哪里

一般根据节点名称来放&#xff0c;如果没有就新建 ComfyUI\models\instantid...

Spring Boot自动配置原理解析

文章目录 前言一、SpringBootConfiguration二、EnableAutoConfiguration2.1、AutoConfigurationPackage2.2、Import(AutoConfigurationImportSelector.class) 三、ComponentScan四、自动配置源码4.1、获取所有候选的自动配置类4.2、过滤不满足条件的自动配置 总结 前言 在常规的…...

LlamaIndex实现(基于PDF|CSV文件)RAG检索增强生成:NaiveRAG

什么是 RAG&#xff1f; RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09; 是一种结合 信息检索&#xff08;Retrieval&#xff09; 和 文本生成&#xff08;Generation&#xff09; 的AI技术&#xff0c;用于提升大语言模型&#xff08;L…...

分布式系统面试总结:3、分布式锁(和本地锁的区别、特点、常见实现方案)

仅供自学回顾使用&#xff0c;请支持javaGuide原版书籍。 本篇文章涉及到的分布式锁&#xff0c;在本人其他文章中也有涉及。 《JUC&#xff1a;三、两阶段终止模式、死锁的jconsole检测、乐观锁&#xff08;版本号机制CAS实现&#xff09;悲观锁》&#xff1a;https://blog.…...

vue3搭建实战项目笔记三

vue3搭建实战项目笔记三 3.1.行高偏移问题3.2.谷歌浏览器上不能定位3.2.2 移动端css隐藏滚动条 3.3.获取列表的数据3.3.1 服务器返回十万条数据3.3.2 分页展示数据3.3.2 防止展示数据为空报错 3.4.上拉加载数据3.4.1 加载更多数据3.4.2 监听页面滚动到底部3.4.3 监听滚动的时机…...

【商城实战(101)】电商未来已来:新技术引领商城发展新航向

【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配,乃至运营推广策略,102 章内容层层递进。无论是想…...

深入解析最大公约数(GCD)与最小公倍数(LCM)的C++实现

深入解析最大公约数&#xff08;GCD&#xff09;与最小公倍数&#xff08;LCM&#xff09;的C实现 一、GCD与LCM的数学定义 1. 最大公约数&#xff08;GCD&#xff09; 两个或多个整数共有约数中最大的一个。 例如&#xff1a; GCD(12, 18) 6GCD(21, 14) 7 2. 最小公倍数…...

低功耗LPWAN模块开发指南:远距离无线通信与边缘计算融合实战‌

在远程资产追踪、野外环境监测等场景中&#xff0c;稳定可靠的长距离通信与超低功耗是系统设计的核心挑战。eFish-SBC-RK3576通过 ‌原生双UART接口 USB OTG扩展能力‌ &#xff0c;可无缝集成主流LPWAN模组&#xff08;LoRa/NB-IoT&#xff09;&#xff0c;实现“数据采集-边…...

【质量管理】纠正、纠正措施和预防的区别与解决问题的四重境界

“质量的定义就是符合要求”&#xff0c;我们在文章【质量管理】人们对于质量的五个错误观念-CSDN博客中提到过&#xff0c;这也是质量大师克劳士比所说的。“质量的系统就是预防”&#xff0c;防止出现产品不良而造成的质量损失。 质量问题的解决可以从微观和宏观两个方面来考…...

STM32F103_LL库+寄存器学习笔记12 - 提高串口通讯程序的健壮性:异常监控 + 超时保护机制

导言 首先&#xff0c;进行USART和DMA状态监测、记录异常状态并主动处理&#xff0c;是高健壮性嵌入式系统开发的核心思想之一。 这种机制看似复杂&#xff0c;实则能有效保障系统长期、稳定地运行&#xff1a; 提升通讯可靠性。降低维护成本。增强系统自恢复能力。 因此&…...

搜索-BFS

马上蓝桥杯了&#xff0c;最近刷了广搜&#xff0c;感觉挺有意思的&#xff0c;广搜题类型都差不多&#xff0c;模板也一样&#xff0c;大家写的时候可以直接套模板 这里给大家讲一个比较经典的广搜题-迷宫 题目问问能否走到 (n,m) 位置&#xff0c;假设最后一个点是我们的&…...

Keil调试(RTT Debug 断点)

调试 打印操作 方式接口优缺点串口打印TXRX简单,但是占用串口,速度慢,重定向fputc简单RTT打印SWDIOSWCLK速度快,不占额外接口,直接移植RTT库断点打印SWDIOSWCLKDebug的时候断点操作SWOSWDIOSWCLKSWO需要连接SWO引脚,重定向fputc简单 这里我只介绍RTT打印和断点打印; 一. RT…...

【jQuery】插件

目录 一、 jQuery插件 1. 瀑布流插件&#xff1a; jQuery 之家 http://www.htmleaf.com/ 2. 图片懒加载&#xff1a; jQuery 插件库 http://www.jq22.com/ 3. 全屏滚动 总结不易~ 本章节对我有很大收获&#xff0c;希望对你也是~~~ 一、 jQuery插件 jQuery 功能…...

leetcode 28 Find the Index of the First Occurrence in a String

直接用kmp算法 class Solution { public:int strStr(string haystack, string needle) {return kmp(haystack,needle);}int kmp(std::string &text,std::string &pattern){int n text.size();int m pattern.size();if(m 0)return 0;std::vector<int> next;ne…...

nginx 动静分离

一.动静分离 1.动静分离的好处 Apache Tocmat 严格来说是一款java EE服务器&#xff0c;主要是用来处理 servlet请求。处理css、js、图片这些静态文件的IO性能不够好&#xff0c;因此&#xff0c;将静态文件交给nginx处理&#xff0c;可以提高系统的访问速度&#xff0c;减少…...

1.2 斐波那契数列模型:LeetCode 面试题 08.01. 三步问题

动态规划解三步问题&#xff1a;LeetCode 面试题 08.01. 三步问题 1. 题目链接 LeetCode 面试题 08.01. 三步问题 题目要求&#xff1a;小孩上楼梯&#xff0c;每次可以走1、2或3步&#xff0c;计算到达第 n 阶台阶的不同方式数&#xff0c;结果需对 1e9 7 取模。 2. 题目描述…...

关于AutoMapper

AutoMapper 概述 AutoMapper 是一个基于约定的对象 - 对象映射库&#xff0c;主要用于在不同对象类型之间自动映射属性值。它能根据配置的映射规则&#xff0c;将源对象的属性值填充到目标对象中&#xff0c;避免了手动编写大量繁琐的对象映射代码。 作用 提升开发效率&…...

是否每一层之间都要线性变换和激活函数?

1. 神经网络层的基本组成 一个典型的神经网络层通常包含两个步骤&#xff1a; 线性变换&#xff08;加权求和&#xff09;&#xff1a; z Wx} b 其中W 是权重矩阵&#xff0c;b是偏置向量&#xff0c;是输入&#xff0c;z 是线性输出。激活函数&#xff1a; 其中&#xff0c…...

golang 的reflect包的常用方法

目录 reflect 包方法总结 类型 (Type) 方法 值 (Value) 方法 代码示例&#xff1a; reflect 包方法总结 p : Person{Name: "小明", Age: 22}t : reflect.TypeOf(&p)v : reflect.ValueOf(p) 类型 (Type) 方法 方法名描述示例               Na…...

CentOS 7 安装 EMQX (MQTT)

CentOS 7 安装 EMQX 通过 Yum 源安装 EMQX 支持通过 Yum 源安装&#xff0c;您可通过以下 Yum 命令从中自动下载和安装 EMQX。 通过以下命令配置 EMQX Yum 源&#xff1a; curl -s https://assets.emqx.com/scripts/install-emqx-rpm.sh | sudo bash安装以下依赖项&#xff…...

Flask项目部署:Flask + uWSGI + Nginx

目录 1,网络架构 2,环境安装 2.1,安装yum:Shell软件包管理器 2.2 安装python 2.3 安装uWSGI 2.4 安装Flask 3,上传工程包到服务器,打包Flask项目 4,创建和配置 uwsgi 配置文件 uwsgi.ini 4.1配置文件 4.2配置文件注释详解 5,启动服务 6,安装nginx 7,nginx配置 8,…...

软件工程面试题(十五)

1、servlet 创建过程以及ruquest,response,session的生命周期? Servlet的创建过程: 第一步 public class AAA extends HttpServlet{ 实现对应的doxxx方法 } 第二步: 在web.xml中配置 <servlet> <servlet-name></servlet-name> <servlet-c…...

当Kafka化身抽水马桶:论组件并发提升与系统可用性的量子纠缠关系

《当Kafka化身抽水马桶&#xff1a;论组件并发提升与系统可用性的量子纠缠关系》 引言&#xff1a;一场OOM引发的血案 某个月黑风高的夜晚&#xff0c;监控系统突然发出刺耳的警报——我们的数据发现流水线集体扑街。事后复盘发现&#xff1a;Kafka集群、Gateway、Discovery服…...

python和Java的区别

Python和Java是两种流行的编程语言&#xff0c;它们之间有一些重要的区别&#xff1a; 语法&#xff1a;Python是一种动态类型的脚本语言&#xff0c;语法简洁明了&#xff0c;通常使用缩进来表示代码块。Java是一种静态类型的编程语言&#xff0c;语法更为严格&#xff0c;需要…...

QFlightInstruments飞行仪表控件库

QFlightInstruments 是一个开源的飞行仪表控件库&#xff0c;专为基于 Qt 的应用程序设计。它提供了一系列仿真实飞机仪表的组件&#xff0c;适用于飞行模拟软件、航空电子系统或任何需要高仿真飞行仪表显示的项目。 主要功能 高仿真飞行仪表&#xff1a;包括空速表、高度表、…...

可发1区的超级创新思路(python\matlab实现):MPTS+Lconv+注意力集成机制的Transformer时间序列模型

首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 应用场景 该模型主要用于时间序列数据预测问题,包含功率预测、电池寿命预测、电机故障检测等等。 一、模型整体架构(本文以光伏功率预测为例) 本模型由多尺度特征提取模块(MPTS)…...

Nginx — Nginx版本升级

例如&#xff1a;将10.224.11.220、10.224.11.221、10.208.11.220 三台服务器上的Nginx从1.21.1版本升级到1.23.3版本。 一、Nginx升级步骤 步骤一&#xff1a;备份老版本的Nginx&#xff08;10.224.11.220、10.224.11.221、10.208.11.220&#xff09; #关闭Nginx cd /usr/l…...

CSS学习笔记6——网页布局

目录 一、元素的浮动属性、清除浮动 清除浮动的其他方法 1、使用空标签清除浮动影响 2、使用overflow属性清除浮动 3、使用伪元素清除浮动影响 原理 overflow属性 二、元素的定位 1、相对定位 2、绝对定位 ​编辑 3、固定定位 z-index层叠等级属性 一、元素的浮动…...

C语言【指针二】

引言 介绍&#xff1a;const修饰指针&#xff0c;野指针 应用&#xff1a;指针的使用&#xff08;strlen的模拟实现&#xff09;&#xff0c;传值调用和传指调用 一、const修饰指针 1.const修饰变量 简单回顾一下前面学过的const修饰变量&#xff1a;在变量前面加上const&…...

第十六届蓝桥杯模拟二(串口通信)

由硬件框图可以知道我们要配置LED 和按键 一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹,code中添加fun.…...

Java List 集合取交集、并集、差集、补集

在Java中&#xff0c;集合操作是编程中非常常见的需求&#xff0c;尤其是在处理数据集合时&#xff0c;如List、Set等。本文将详细介绍如何在Java中实现List集合的交集、并集、差集和补集操作&#xff0c;并提供代码示例和实现方法。 1. 交集操作 交集是指两个集合中都存在的元…...

SkyWalking+Springboot实战

1、下载SkyWalking APM 1.手动下载 Downloads | Apache SkyWalkinghttps://skywalking.apache.org/downloads/ 2.链接下载 https://dlcdn.apache.org/skywalking/10.2.0/apache-skywalking-apm-10.2.0.tar.gzhttps://dlcdn.apache.org/skywalking/10.2.0/apache-skywalking-…...

【小兔鲜】day01 项目、Vue3介绍、组合式API、小案例

【小兔鲜】day01 项目、Vue3介绍、组合式API、小案例 0. 市场上Vue前端工程师用到的技术1. Vue3小兔鲜先导课1.1 技术栈1.2 项目规模1.3 项目亮点1.4 课程安排 2. 认识Vue32.1 Vue3组合式API体验 3. create-vue创建Vue3项目3.1 新建项目结构3.2 小节3.3 补充说明npm init vuela…...

【Pandas DataFrame】

以下是 Pandas DataFrame 的核心知识点总结&#xff0c;用结构化分类帮你高效记忆关键操作和概念&#xff1a; 1. 基础操作 创建DataFrame 方法代码示例说明从字典创建df pd.DataFrame({A: [1,2], B: [3,4]})字典键为列名&#xff0c;值为数据从列表创建df pd.DataFrame([[…...

华为OD机试2025A卷 - 生成回文素数(Java Python JS C++ C )

最新华为OD机试 真题目录:点击查看目录 华为OD面试真题精选:点击立即查看 题目描述 求出大于或等于 N 的最小回文素数。 如果一个数大于 1,且其因数只有 1 和它自身,那么这个数是素数。 例如,2,3,5,7,11 以及 13 是素数。 如果一个数从左往右读与从右往左读是一…...