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

PL/SQL

一、Function

语法:

CREATE [OR REPLACE] FUNCTION FunctionName(param1 [IN|OUT|IN OUT] NUMBER,param1 [IN|OUT|IN OUT] VARCHAR2)
RETURN VARCHAR2
IS 
--声明变量、游标、常量等
--基本变量声明
v_employee_name VARCHAR2(100); 		--字符串变量
v_salary NUMBER(10,2);						--数字变量
v_hire_date DATE;									--日期变量
v_is_active BOOLEAN := TRUE;      --布尔变量
v_department_id NUMBER := 10;     --初始值数字变量
--复杂变量声明--基于表字段类型的变量
v_emp_record employees%ROWTYPE;   --记录类型,匹配employee表结构--基于表字段的变量
v_dept_name departments.department_name%TYPE;--声明一个变量 v_dept_name,其数据类型与 departments 表中 department_name 列的数据类型完全一致。--基本游标的声明
CURSOR c_employees ISSELECT employee_id,last_name,salaryFROM employeesWHERE department_id = 10;--在 PL/SQL 中逐行处理 employees 表中 department_id = 10 的员工数据。
--带参数的游标
CURSOR c_dept_employees(p_dept_id NUMBER) ISSELECT employee_id,last_nameFROM employeesWHERE department_id = dept_id;--通过参数 p_dept_id 可以灵活查询不同部门的员工,无需为每个部门编写单独的游标。--弱类型游标变量 (Weakly Typed REF CURSOR)
--不指定返回结构:可以关联到任何 SELECT 语句
--灵活性高:同一个游标变量可以在不同时间指向不同的查询
--类型安全低:需要在运行时才知道返回的数据结构TYPE t_emp_cursor IS REF CURSOR;cv_emp t_emp_cursor;--强类型游标变量 (Strongly Typed REF CURSOR)
--指定返回类型:必须返回与定义匹配的结构
--类型安全高:编译时检查,避免运行时错误
--可维护性好:明确知道游标返回的数据结构TYPE t_dept_cursor IS REF CURSOR RETURN departments%ROWTYPE;cv_dept t_dept_cursor;--基本常量
c_company_name CONSTANT VARCHAR2(100) :='Oracle Corporation';
c_pi CONSTANT NUMBER :=3.1415926;
c_tax_rate CONSTANT NUMBER(5,4) :=0.0825;-- 8.25%的税率  第一个数字(5):表示这个数的总位数(包括整数位和小数位)第二个数字(4):表示小数部分的位数--基于函数的常量
c_user CONSTANT VARCHAR2(30) :=USER;
c_current_date CONSTANT DATE := SYSDATE;
  1. 命名规范
    • 变量:v_前缀 (如 v_salary)
    • 常量:c_前缀 (如 c_pi)
    • 游标:c_前缀 (如 c_employees)
    • 参数:p_前缀 (如 p_dept_id)
  1. 初始化
    • 变量可以不初始化,但建议初始化
    • 常量必须在声明时初始化
  1. 作用域
    • 在DECLARE部分声明的变量只在当前块中有效
    • 嵌套块中可以访问外部块变量,除非被同名变量覆盖
  1. 数据类型
    • 优先使用%TYPE和%ROWTYPE,使代码更灵活
    • 避免使用过大的VARCHAR2尺寸,合理估计需求

带参数的游标和固定条件游标:

特性

带参数游标

固定条件游标

灵活性

高(可动态改变查询条件)

低(条件固定)

代码复用性

高(一个游标多处使用)

低(每个条件需单独游标)

维护成本

低(只需维护一个游标)

高(需维护多个相似游标)

内存占用

每次只处理一个游标实例

可能同时存在多个游标实例

弱类型游标变量、强类型游标变量的区别:

特性

弱类型游标变量 (IS REF CURSOR

)

强类型游标变量 (IS REF CURSOR RETURN...

)

类型约束

无,可关联任何查询

必须返回指定类型的记录

类型安全

低(运行时可能出错)

高(编译时检查)

灵活性

高(可重用不同查询)

低(只能用于特定结构查询)

代码可读性

较差(不知道返回结构)

较好(明确知道返回结构)

典型用途

动态SQL、通用数据处理程序

明确数据结构的业务逻辑

CREATE OR REPLACE PROCEDURE calculate_employee_bonus(p_dept_id IN NUMBER,p_bonus_rate IN NUMBER,p_total_bonus OUT NUMBER
)
IS-- 常量声明c_min_salary CONSTANT NUMBER := 3000;c_max_bonus CONSTANT NUMBER := 10000;-- 变量声明v_dept_name departments.department_name%TYPE;v_eligible_count NUMBER := 0;v_bonus_pool NUMBER := 0;-- 游标声明CURSOR c_eligible_emps ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = p_dept_idAND salary > c_min_salary;-- 记录类型TYPE t_bonus_rec IS RECORD (emp_id employees.employee_id%TYPE,emp_name VARCHAR2(100),bonus_amount NUMBER(10,2));r_bonus t_bonus_rec;BEGIN-- 获取部门名称SELECT department_name INTO v_dept_nameFROM departmentsWHERE department_id = p_dept_id;DBMS_OUTPUT.PUT_LINE('Processing department: ' || v_dept_name);-- 处理游标FOR emp_rec IN c_eligible_emps LOOPv_eligible_count := v_eligible_count + 1;-- 计算奖金r_bonus.emp_id := emp_rec.employee_id;r_bonus.emp_name := emp_rec.last_name;r_bonus.bonus_amount := LEAST(emp_rec.salary * p_bonus_rate, c_max_bonus);v_bonus_pool := v_bonus_pool + r_bonus.bonus_amount;DBMS_OUTPUT.PUT_LINE('Employee: ' || r_bonus.emp_name || ', Bonus: ' || r_bonus.bonus_amount);END LOOP;p_total_bonus := v_bonus_pool;DBMS_OUTPUT.PUT_LINE('Total eligible employees: ' || v_eligible_count);DBMS_OUTPUT.PUT_LINE('Total bonus pool: ' || v_bonus_pool);EXCEPTIONWHEN NO_DATA_FOUND THENDBMS_OUTPUT.PUT_LINE('Department not found: ' || p_dept_id);p_total_bonus := 0;WHEN OTHERS THENDBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);p_total_bonus := -1; -- 错误标识
END calculate_employee_bonus;
  1. 返回值:必须使用RETURN语句返回一个值
  2. 参数模式
    • IN(默认):输入参数
    • OUT:输出参数
    • IN OUT:既可输入又可输出
  1. 调用方式:可在SQL语句中直接调用
  2. 命名冲突:避免与内置函数同名

二、Procedure 存储过程

语法

CREATE [OR REPLACE] PROCEDURE 过程名(参数1 [IN|OUT|IN OUT] 数据类型,参数2 [IN|OUT|IN OUT] 数据类型,...
)
IS-- 声明部分(变量、常量、游标等)
BEGIN-- 执行部分(业务逻辑)
EXCEPTION-- 异常处理部分
END 过程名;
  1. 无返回值:与函数不同,过程不直接返回值
  2. 参数模式:可以使用OUT参数返回多个值
  3. 调用方式:必须使用EXECUTE或CALL语句
  4. 事务控制:过程中可以包含COMMIT/ROLLBACK
CREATE OR REPLACE PROCEDURE update_employee_salary(p_emp_id IN NUMBER,p_increase IN NUMBER,p_new_salary OUT NUMBER,p_status OUT VARCHAR2
)
ISv_current_salary NUMBER;
BEGIN-- 获取当前薪资SELECT salary INTO v_current_salary FROM employees WHERE employee_id = p_emp_id;-- 更新薪资UPDATE employees SET salary = salary + p_increase WHERE employee_id = p_emp_id;-- 设置输出参数p_new_salary := v_current_salary + p_increase;p_status := 'SUCCESS';COMMIT;
EXCEPTIONWHEN NO_DATA_FOUND THENp_status := 'EMPLOYEE_NOT_FOUND';p_new_salary := 0;WHEN OTHERS THENROLLBACK;p_status := 'ERROR: ' || SQLERRM;p_new_salary := 0;
END update_employee_salary;

三、显式游标

1.基本遍历(显式游标)

DECLARECURSOR c_employees ISSELECT employee_id, last_name, salaryFROM employeesWHERE department_id = 10;r_emp c_employees%ROWTYPE; -- 定义记录变量
BEGINOPEN c_employees;          -- 打开游标LOOPFETCH c_employees INTO r_emp; -- 提取一行EXIT WHEN c_employees%NOTFOUND; -- 退出条件DBMS_OUTPUT.PUT_LINE('ID: ' || r_emp.employee_id || ', Name: ' || r_emp.last_name || ', Salary: ' || r_emp.salary);END LOOP;CLOSE c_employees; -- 关闭游标
END;

关键特点

特性

说明

惰性加载

只有调用 FETCH

时才真正从数据库获取数据,节省内存

精确控制

可手动控制游标的打开(OPEN

)、获取(FETCH

)、关闭(CLOSE

)时机

可参数化

支持传递参数(如 CURSOR c_dept(p_dept_id NUMBER) IS SELECT...

性能优化

比隐式游标(如 FOR x IN (SELECT ...)

)更灵活,适合复杂数据处理逻辑

何时选择显式游标?

  • 需要复用查询逻辑时
  • 需要精细控制数据提取过程时
  • 使用 BULK COLLECT 批量操作时
  • 查询非常复杂,需明确分离 SQL 和 PL/SQL 逻辑时
-- 隐式游标(自动管理,但灵活性低)
BEGINFOR emp IN (SELECT employee_id, last_name FROM employees WHERE department_id = 10) LOOP-- 直接使用 emp.employee_id, emp.last_nameEND LOOP;
END;

实际应用场景

  1. 数据迁移
    逐行处理源表数据并插入到目标表。
  2. 报表生成
    遍历数据计算统计指标(如部门平均薪资)。
  3. 数据校验
    检查每行数据是否符合业务规则。
  4. 批量更新
    根据游标结果批量修改其他表的数据。

2.简化遍历(FOR循环)

BEGINFOR emp_rec IN c_employees LOOP -- 自动打开/关闭游标DBMS_OUTPUT.PUT_LINE('ID: ' || emp_rec.employee_id || ', Name: ' || emp_rec.last_name);END LOOP;
END;

3.批量处理(BULK COLLECT)

DECLARETYPE t_emp_tab IS TABLE OF c_employees%ROWTYPE;v_emps t_emp_tab;
BEGINOPEN c_employees;FETCH c_employees BULK COLLECT INTO v_emps; -- 批量提取CLOSE c_employees;-- 处理批量数据FOR i IN 1..v_emps.COUNT LOOP-- 业务逻辑...END LOOP;
END;

http://www.dtcms.com/a/302840.html

相关文章:

  • 开疆智能ModbusRTU转Profinet网关连接西门子CP341配置案例
  • DDD之整体设计流程(2)
  • debian系统分卷是不会影响系统启动速度?
  • 排序算法 (Sorting Algorithms)-Python示例
  • Android 系统架构
  • 阿里云 API 网关 x OKG:游戏连接治理的「最后一公里」
  • 阿里云正式开源 LoongSuite:打造 AI 时代的高性能低成本可观测采集套件
  • 电脑不小心误删了文件怎么恢复??
  • AI资讯日报 - 2025年07月28日
  • EXCEL批量生成超链接引用无效的情况
  • Kotlin中Flow
  • 基于Spring Boot的装饰工程管理系统(源码+论文)
  • 一个典型的微控制器MCU包含哪些模块?
  • kafka开启Kerberos使用方式
  • “本地计算机上的 mysql 服务启动后停止,某些服务在未由其他服务或程序使用时将自动停止”解决方式
  • 算法训练营day34 动态规划② 62.不同路径、63. 不同路径 II、343整数拆分、96.不同的二叉搜索树
  • Kafka 顺序消费实现与优化策略
  • linux diff命令使用教程
  • 最长连续数组
  • 【C++11】列表初始化【{ }使用详解】
  • Facenet(MTCNN+InceptionResnetV1)人脸考勤项目(有缺点,但可用)
  • 境外期货Level2高频Tick历史行情数据获取与应用指南
  • 基于LangGraph Cli的智能数据分析助手
  • MCU 中的 PWM(脉冲宽度调制)是什么?
  • 八大神经网络的区别
  • Java Stream流的使用
  • Open CV图像基本操作可莉版
  • Linux:线程同步与线程互斥
  • PBR技术
  • 杭州网站建设公司,哪家擅长做多语言外贸站?