【Oracle】PL/SQL 显式游标、隐式游标、动态游标
在PL/SQL块中执行SELECT、INSERT、DELETE和UPDATE语句时,Oracle会在内存中为其分配上下文区(Context Area),即缓冲区。游标是指向该区的一个指针,或是命名一个工作区(Work Area),或是一种结构化数据类型。
在每个用户会话中,可以同时打开多个游标,其数量由数据库初始化参数文件中的OPEN_CURSORS参数定义。
对于不同的SQL语句,游标的使用情况不同:
|
SQL语句 |
游标 |
|
非查询语句 |
隐式的 |
|
结果是单行的查询语句 |
隐式的或显示的 |
|
结果是多行的查询语句 |
显示的 |
view plain copy print?
- DECLARE
- CURSOR c4(dept_id NUMBER, j_id VARCHAR2) --1、声明游标,有参数没有返回值
- IS
- SELECT first_name f_name, hire_date FROM employees
- WHERE department_id = dept_id AND job_id = j_id;
-
- --基于游标定义记录变量,比声明记录类型变量要方便,不容易出错
- v_emp_record c4%ROWTYPE;
- BEGIN
- OPEN c4(90, 'AD_VP'); --2、打开游标,传递参数值
- LOOP
- FETCH c4 INTO v_emp_record; --3、提取游标fetch into
- IF c4%FOUND THEN
- DBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是'
- ||v_emp_record.hire_date);
- ELSE
- DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');
- EXIT;
- END IF;
- END LOOP;
- CLOSE c4; --4、关闭游标
- END;
退出LOOP或者用:
EXIT WHEN c4%NOTFOUND;
游标属性:
Cursor_name%FOUND 布尔型属性,当最近一次提取游标操作FETCH成功则为 TRUE,否则为FALSE;
Cursor_name%NOTFOUND 布尔型属性,与%FOUND相反;——注意区别于DO_DATA_FOUND(select into抛出异常)
Cursor_name%ISOPEN 布尔型属性,当游标已打开时返回 TRUE;
Cursor_name%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。
view plain copy print?
- DECLARE
- CURSOR c_cursor(dept_no NUMBER DEFAULT 10)
- IS
- SELECT department_name, location_id FROM departments WHERE department_id <= dept_no;
- BEGIN
- --当dept_no参数值为30
- FOR c1_rec IN c_cursor(30) LOOP
- DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);
- END LOOP;
-
- --使用默认的dept_no参数值10
- FOR c1_rec IN c_cursor LOOP
- DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);
- END LOOP;
- END;
或者可以在游标FOR循环语句中使用子查询
- BEGIN
- FOR 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;
view plain copy print?
- DECLARE
- v_rows NUMBER;
- BEGIN
- --更新数据
- UPDATE employees SET salary = 30000
- WHERE 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 THEN
- DELETE FROM departments WHERE department_id=v_deptno;
- END IF;
- END;
view plain copy print?
- 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_deptno
- FOR UPDATE NOWAIT; --1、for update
- BEGIN
- FOR emp_record IN emp_cursor LOOP
- IF emp_record.salary < 1500 THEN
- UPDATE employees SET salary=1500
- WHERE CURRENT OF emp_cursor; --2、WHERE CURRENT OF cursor_name子句
- END IF;
- END LOOP;
- END;
view plain copy print?
- DECLARE
- --定义一个游标数据类型
- TYPE emp_cursor_type IS REF CURSOR;
- --声明一个游标变量
- c1 EMP_CURSOR_TYPE;
- --声明两个记录变量
- v_emp_record employees%ROWTYPE;
- v_reg_record regions%ROWTYPE;
-
- BEGIN
- OPEN c1 FOR SELECT * FROM employees WHERE department_id = 20;
- LOOP
- FETCH c1 INTO v_emp_record;
- EXIT WHEN c1%NOTFOUND;
- DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name||'的雇佣日期是'
- ||v_emp_record.hire_date);
- END LOOP;
- --将同一个游标变量对应到另一个SELECT语句
- OPEN c1 FOR SELECT * FROM regions WHERE region_id IN(1,2);
- LOOP
- FETCH c1 INTO v_reg_record;
- EXIT WHEN c1%NOTFOUND;
- DBMS_OUTPUT.PUT_LINE(v_reg_record.region_id||'表示'
- ||v_reg_record.region_name);
- END LOOP;
- CLOSE c1;
- END;
- DECLARE
- --定义一个游标数据类型
- TYPE emp_cursor_type IS REF CURSOR;
- --声明一个游标变量
- c1 EMP_CURSOR_TYPE;
- --声明两个记录变量
- v_emp_record employees%ROWTYPE;
- v_reg_record regions%ROWTYPE;
- BEGIN
- OPEN c1 FOR SELECT * FROM employees WHERE department_id = 20;
- LOOP
- FETCH c1 INTO v_emp_record;
- EXIT WHEN c1%NOTFOUND;
- DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name||'的雇佣日期是'
- ||v_emp_record.hire_date);
- END LOOP;
- --将同一个游标变量对应到另一个SELECT语句
- OPEN c1 FOR SELECT * FROM regions WHERE region_id IN(1,2);
- LOOP
- FETCH c1 INTO v_reg_record;
- EXIT WHEN c1%NOTFOUND;
- DBMS_OUTPUT.PUT_LINE(v_reg_record.region_id||'表示'
- ||v_reg_record.region_name);
- END LOOP;
- CLOSE c1;
- END;