Oracle游标创建和使用的语法和举例(显示和隐式游标)

游标
注意:与sql的游标定义不同,Oracle游标可以带输入变量和输出类型
            使用游标的时候,可以输入参数,也可以不输入

declear cursor 游标名[(变量名 [in] 类型[:=缺省])]
[return ret_type]
is select query;
其他变量定义;
begin
open 游标名(参数);--/open 游标名;/open 游标名();
fetch 游标名 into 变量;
while 游标名%found loop
sentence;
fetch 游标名 into 变量;
end loop;
close 游标名
end

游标可用使用的几个属性
%found是否获取到数据
%notfound是否没有数据
%rowcount受SQL影响的行数
%isopen游标是否打开状态

显式游标的例子
--使用游标获取岗位为employees的姓名+电话+工资
set serveroutput on;
declare 
cursor my_cursor(var_job varchar2:='ST_MAN') 
is 
select first_name,phone_number,salary from employees where job_id=var_job and rownum <=3;
type my_record is record  
(var_1 employees.first_name%type,
var_2 employees.phone_number%type,
var_3 employees.salary%type
);
var_myrecord my_record;
begin
dbms_output.put_line('下面演示使用while语句遍历显示游标,不输入参数');
open my_cursor;--没有输入参数,取缺省
fetch my_cursor into var_myrecord;
while my_cursor%found loop  --使用游标属性
dbms_output.put_line('员工'||var_myrecord.var_1||'的联系方式为:'||var_myrecord.var_2||',当前工资为:'||var_myrecord.var_3||'。');
fetch my_cursor into var_myrecord;
end loop;
close my_cursor;--不需要输入变量
dbms_output.put_line('下面演示使用while语句遍历显示游标,输入参数');
open my_cursor('ST_CLERK');--输入参数
fetch my_cursor into var_myrecord;
while my_cursor%found loop  --使用游标属性
dbms_output.put_line('员工'||var_myrecord.var_1||'的联系方式为:'||var_myrecord.var_2||',当前工资为:'||var_myrecord.var_3||'。');
fetch my_cursor into var_myrecord;
end loop;
close my_cursor;--不需要输入变量
--使用for语句遍历显示游标
dbms_output.put_line('下面演示使用for语句遍历显示游标,不输入参数');
for var_myrecord2 in my_cursor()
loop
dbms_output.put_line('员工'||var_myrecord2.first_name||'的联系方式为:'||var_myrecord2.phone_number||',当前工资为:'||var_myrecord2.salary||'。');
end loop;
dbms_output.put_line('下面演示使用for语句遍历显示游标,输入参数');
for var_myrecord2 in my_cursor('ST_CLERK')
loop
dbms_output.put_line('员工'||var_myrecord2.first_name||'的联系方式为:'||var_myrecord2.phone_number||',当前工资为:'||var_myrecord2.salary||'。');
end loop;
end;

执行结果
下面演示使用while语句遍历显示游标,不输入参数
员工Matthew的联系方式为:650.123.1234,当前工资为:8000。
员工Adam的联系方式为:650.123.2234,当前工资为:8200。
员工Payam的联系方式为:650.123.3234,当前工资为:7900。
下面演示使用while语句遍历显示游标,输入参数
员工Julia的联系方式为:650.124.1214,当前工资为:3200。
员工Irene的联系方式为:650.124.1224,当前工资为:2700。
员工James的联系方式为:650.124.1334,当前工资为:2400。
下面演示使用for语句遍历显示游标,不输入参数
员工Matthew的联系方式为:650.123.1234,当前工资为:8000。
员工Adam的联系方式为:650.123.2234,当前工资为:8200。
员工Payam的联系方式为:650.123.3234,当前工资为:7900。
下面演示使用for语句遍历显示游标,输入参数
员工Julia的联系方式为:650.124.1214,当前工资为:3200。
员工Irene的联系方式为:650.124.1224,当前工资为:2700。
员工James的联系方式为:650.124.1334,当前工资为:2400。

隐式游标
注意:在一个PL/SQL块中出现多个SQL语句,隐式游标的属性值只反映出紧挨着它上面那条SQL的处理结果
set serveroutput on
begin
update employees set salary=salary+100 where job_id='AD_VP';
if sql%notfound then
dbms_output.put_line('');
else
dbms_output.put_line(sql%rowcount||'个员工调整了工资');
end if;
end;

执行结果:
匿名块已完成
2个员工调整了工资

for循环语句与游标

通过for语句循环游标,显示游标上面已经举例,下面举例隐式游标。

注意此时自动计数器不是整型,而是record类型的变量

set serveroutput on
begin
for var_my_record in ( select first_name,phone_number,salary from employees where job_id='AD_VP' and rownum <=3) 
loop
dbms_output.put_line('员工'||var_my_record.first_name||'的联系方式为:'||var_my_record.phone_number||',当前工资为:'||var_my_record.salary||'。');
end loop;
end;

执行结果:
匿名块已完成
员工Neena的联系方式为:515.123.4568,当前工资为:17200。
员工Lex的联系方式为:515.123.4569,当前工资为:17200。


博文仅供参考,欢迎大家来访。如有错误之处,希望批评指正。
<think>好的,用户想要详细列出之前提到的Oracle存储过程学习中的常用知识点,并给出详细注释示例。首先,我需要回顾之前提供的三天学习计划,提取出涉及的关键概念示例。可能包括变量声明、流程控制、游标使用、存储过程创建参数传递、异常处理等。 用户可能需要每个知识点都有清晰的解释,示例代码以及注释。需要确保注释详细,解释每行代码的作用,这样新手可以理解。同时,要检查语法是否正确,比如使用%TYPE锚定类型,游标的正确写法,异常处理的常见类型等。 还要考虑用户可能对某些概念不太清楚,比如锚定类型或者游标的类型,是否需要进一步说明。另外,示例的复杂度是否适中,是否覆盖了常见的用例,比如增删改查、循环处理数据、异常处理等。 需要组织这些知识点,按逻辑顺序排列,可能从基础到进阶。比如先讲变量数据类型,然后是流程控制,接着是游标,然后是存储过程的创建参数,最后是异常处理。每个部分都需要有示例代码注释,确保用户能够逐步理解。 还需要注意使用正确的中文术语,避免翻译错误。例如,“cursor”翻译为“游标”,“procedure”翻译为“存储过程”。检查示例中的SQLPL/SQL语法是否正确,比如存储过程的创建语句是否包含AS或IS,参数的正确写法等。 可能用户在实际操作中会遇到问题,比如如何执行存储过程,如何处理结果,所以示例中的注释需要详细说明如何测试或调用这些过程。例如,在创建带有OUT参数的存储过程后,如何调用并获取结果。 此外,异常处理部分需要列出常见的异常类型,如NO_DATA_FOUND、TOO_MANY_ROWS等,并说明在什么情况下会触发这些异常,如何处理它们。同时,事务控制如COMMITROLLBACK的位置使用场景也需要解释清楚。 最后,确保整个回答结构清晰,每个知识点有标题,示例代码块,注释部分可以用中文在代码中或代码下方解释。可能还需要总结这些知识点,帮助用户复习巩固。</think>以下是从Oracle存储过程学习中提炼的核心知识点及详细示例说明,所有代码均包含注释: --- ### **一、PL/SQL基础结构** #### 1. 匿名块与输出 ```sql DECLARE -- 声明部分(可选) v_text VARCHAR2(50) := 'Hello PL/SQL'; -- 定义字符串变量 BEGIN -- 执行部分(必须) DBMS_OUTPUT.PUT_LINE(v_text); -- 输出内容到控制台 EXCEPTION -- 异常处理(可选) WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error!'); END; -- 结束标记 ``` #### 2. 变量声明 ```sql DECLARE v_count NUMBER := 0; -- 数字类型 v_date DATE := SYSDATE; -- 日期类型 v_name employees.last_name%TYPE; -- 使用%TYPE锚定字段类型 BEGIN SELECT last_name INTO v_name -- 将查询结果存入变量 FROM employees WHERE employee_id = 100; END; ``` --- ### **二、流程控制** #### 1. IF条件语句 ```sql DECLARE v_score NUMBER := 85; BEGIN IF v_score >= 90 THEN DBMS_OUTPUT.PUT_LINE('优秀'); ELSIF v_score >= 60 THEN -- 注意是ELSIF不是ELSEIF DBMS_OUTPUT.PUT_LINE('合格'); ELSE DBMS_OUTPUT.PUT_LINE('不合格'); END IF; END; ``` #### 2. FOR循环 ```sql BEGIN FOR i IN 1..5 LOOP -- 循环5次(1到5) DBMS_OUTPUT.PUT_LINE('当前值: ' || i); END LOOP; END; ``` #### 3. WHILE循环 ```sql DECLARE v_num NUMBER := 3; BEGIN WHILE v_num > 0 LOOP DBMS_OUTPUT.PUT_LINE('剩余次数: ' || v_num); v_num := v_num - 1; END LOOP; END; ``` --- ### **三、游标(Cursor)** #### 1. 显游标 ```sql DECLARE CURSOR emp_cur IS -- 定义游标 SELECT employee_id, last_name FROM employees WHERE department_id = 50; v_emp_id employees.employee_id%TYPE; v_emp_name employees.last_name%TYPE; BEGIN OPEN emp_cur; -- 打开游标 LOOP FETCH emp_cur INTO v_emp_id, v_emp_name; -- 提取数据 EXIT WHEN emp_cur%NOTFOUND; -- 无数据时退出循环 DBMS_OUTPUT.PUT_LINE(v_emp_id || ': ' || v_emp_name); END LOOP; CLOSE emp_cur; -- 关闭游标 END; ``` #### 2. FOR游标简化版 ```sql BEGIN FOR rec IN (SELECT * FROM employees WHERE salary > 8000) -- 打开/关闭游标 LOOP DBMS_OUTPUT.PUT_LINE(rec.last_name || '的工资: ' || rec.salary); END LOOP; END; ``` --- ### **四、存储过程** #### 1. 基本存储过程 ```sql CREATE OR REPLACE PROCEDURE raise_salary ( -- 创建或替换存储过程 p_emp_id IN NUMBER, -- 输入参数 p_percent IN NUMBER ) AS v_current_salary NUMBER; BEGIN SELECT salary INTO v_current_salary -- 查询当前工资 FROM employees WHERE employee_id = p_emp_id; UPDATE employees SET salary = salary * (1 + p_percent/100) -- 更新工资 WHERE employee_id = p_emp_id; COMMIT; -- 提交事务 DBMS_OUTPUT.PUT_LINE('ID ' || p_emp_id || ' 工资从 ' || v_current_salary || ' 调整为 ' || (v_current_salary * (1 + p_percent/100))); EXCEPTION WHEN NO_DATA_FOUND THEN -- 捕获无数据异常 DBMS_OUTPUT.PUT_LINE('员工不存在!'); END raise_salary; ``` #### 2. 带OUT参数的存储过程 ```sql CREATE OR REPLACE PROCEDURE get_employee_info ( p_emp_id IN NUMBER, o_name OUT VARCHAR2, -- 输出参数 o_salary OUT NUMBER ) AS BEGIN SELECT last_name, salary INTO o_name, o_salary -- 将结果存入输出参数 FROM employees WHERE employee_id = p_emp_id; END get_employee_info; ``` --- ### **五、异常处理** #### 1. 预定义异常 ```sql BEGIN INSERT INTO departments (department_id, department_name) VALUES (100, 'IT'); -- 假设主键100已存在 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN -- 捕获唯一约束冲突 DBMS_OUTPUT.PUT_LINE('部门ID已存在!'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('错误代码: ' || SQLCODE); END; ``` #### 2. 自定义异常 ```sql DECLARE e_salary_too_high EXCEPTION; -- 自定义异常 PRAGMA EXCEPTION_INIT(e_salary_too_high, -20001); -- 绑定错误代码 BEGIN IF :new.salary > 50000 THEN RAISE e_salary_too_high; -- 抛出异常 END IF; EXCEPTION WHEN e_salary_too_high THEN RAISE_APPLICATION_ERROR(-20001, '薪资超过上限'); -- 抛出应用错误 END; ``` --- ### **六、事务控制** ```sql CREATE OR REPLACE PROCEDURE transfer_funds ( from_acc NUMBER, to_acc NUMBER, amount NUMBER ) AS BEGIN UPDATE accounts SET balance = balance - amount WHERE acc_id = from_acc; UPDATE accounts SET balance = balance + amount WHERE acc_id = to_acc; COMMIT; -- 提交事务 EXCEPTION WHEN OTHERS THEN ROLLBACK; -- 回滚事务 DBMS_OUTPUT.PUT_LINE('交易失败: ' || SQLERRM); END transfer_funds; ``` --- ### **关键知识点总结表** | 类别 | 核心内容 | |----------------|--------------------------------------------------------------------------| | **变量声明** | %TYPE锚定类型、变量作用域、常量定义 | | **流程控制** | IF-ELSIF-ELSE结构、基本循环(LOOP/WHILE/FOR) | | **游标操作** | 显游标声明/打开/提取/关闭、游标属性(%FOUND/%ROWCOUNT) | | **存储过程** | CREATE PROCEDURE语法、IN/OUT参数、局部变量定义 | | **异常处理** | 预定义异常(NO_DATA_FOUND)、自定义异常、SQLCODE/SQLERRM使用 | | **事务控制** | COMMIT提交、ROLLBACK回滚、SAVEPOINT保存点 | --- ### **调试技巧** 1. **输出调试**:使用`DBMS_OUTPUT.PUT_LINE`打印变量值 2. **异常定位**:在EXCEPTION块中输出`SQLERRM`获取错误详情 3. **单步调试**:在SQL Developer中右键过程选择"Debug" 4. **日志记录**:建议重要操作写入日志表而非仅依赖控制台输出 掌握这些知识点后,可通过Oracle官方文档扩展学习包(package)、函数(function)等高级内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值