PLSQL循环自定义函数与存储过程实战案例详解
今天,咱们来系统地梳理一下PL/SQL编程中三个最核心、也最实用的部分:循环结构、自定义函数以及存储过程。掌握了这三块内容,基本上就能应对日常开发中八成以上的场景了。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

简单来说,这篇文章会带你搞懂:
循环结构:怎么用FOR循环处理固定次数的任务,用WHILE循环应对条件不确定的情况,以及如何用BREAK、CONTINUE这些控制语句让循环更灵活。
自定义函数:重点在于它“必须有返回值”的特性,我们会看看它在数值计算和业务查询里是怎么发挥作用的。
存储过程:它的主战场是封装复杂的数据处理流程,我们会把它和函数做个清晰对比,比如它没有返回值,也不能直接在SQL里调用。
另外,还会特别提醒一个容易被忽略的语法细节:存储过程里的IS或AS关键字,是绝对不能省的。文章最后也准备了一些典型的练习题,建议你亲手敲一遍代码,理解会更深刻。
无论你是正在学习Oracle数据库的开发新手,还是想巩固一下PL/SQL基础的老手,这篇内容都能帮你快速抓住重点。
一、循环结构
在PL/SQL里写业务逻辑,循环是绕不开的。主要有两种:FOR循环和WHILE循环,用对了场景,代码会简洁高效很多。
1. FOR 循环(最常用)
当你明确知道要循环多少次的时候,FOR循环就是首选。它的语法非常直观:
FOR I IN 起始值..结束值 LOOP 循环体; END LOOP;
- 循环变量
I会自动从起始值递增到结束值,而且步长固定为1,没法改。 - 这里有个细节需要注意:
起始值..结束值定义的是一个闭区间。也就是说,循环变量I会遍历从起始值到结束值的每一个整数,包括结束值本身。
举个例子,FOR I IN 1..5 LOOP,I会依次取1, 2, 3, 4, 5。
示例:判断质数
比如,我们想判断一个数X是不是质数,思路就是看它能不能被2到X-1之间的数整除:
DECLARE
X NUMBER := &请输入数值;
V_FLAG NUMBER := 0; -- 0表示是质数,1表示不是
BEGIN
FOR I IN 2..X-1 LOOP
IF MOD(X, I) = 0 THEN
V_FLAG := 1; -- 能被整除,不是质数
EXIT; -- 发现一个因子就可以退出了,用EXIT跳出循环
END IF;
END LOOP;
... -- 后续根据V_FLAG输出结果
END;
示例:99乘法表
再来个经典的双重FOR循环例子——打印九九乘法表:
DECLARE
V_STR VARCHAR2(100);
BEGIN
FOR I IN 1..9 LOOP
V_STR := ''; -- 每一行开始时清空字符串
FOR J IN 1..I LOOP -- 注意内层循环到I为止
V_STR := V_STR || I || ' * ' || J || ' = ' || I*J || ' ';
END LOOP;
DBMS_OUTPUT.PUT_LINE(V_STR); -- 输出一整行
END LOOP;
END;
2. WHILE 循环
如果循环次数不确定,但只要满足某个条件就要继续执行,那就轮到WHILE循环上场了。
WHILE 条件 LOOP 循环体; 变量自增/自减; -- 千万别忘了这步,否则容易死循环 END LOOP;
示例:输出1~100的奇数
DECLARE
V_NUM NUMBER := 1;
BEGIN
WHILE V_NUM <= 100 LOOP
IF MOD(V_NUM,2) = 1 THEN
DBMS_OUTPUT.PUT_LINE(V_NUM);
END IF;
V_NUM := V_NUM + 1; -- 手动控制循环变量递增
END LOOP;
END;
3. 循环控制语句(重要!)
想让循环更智能,离不开这几个控制关键字:
| 关键字 | 作用说明 |
|---|---|
EXIT (或 BREAK) | 立刻终止当前所在的循环,然后继续执行循环后面的代码。 |
CONTINUE | 跳过本次循环体内剩下的语句,直接开始下一次循环。 |
RETURN | 这个比较“狠”,直接结束整个程序(或函数/过程),后面的代码都不执行了。 |
在刚才的质数判断例子里,我们用到的EXIT就是典型的应用——一旦找到因子,就没必要继续循环了。
二、自定义函数(FUNCTION)
函数,顾名思义,就是用来干“计算并返回一个结果”这件事的。它在SQL语句里也能直接调用,非常方便。
语法结构
CREATE OR REPLACE FUNCTION 函数名(入参名 参数类型) RETURN 返回值类型 IS 变量声明; BEGIN 逻辑体; RETURN 结果; -- 必须有RETURN语句 END;
特点
- 必须有返回值:这是函数最根本的特征。
- 参数类型不定义长度:声明入参和返回值类型时,比如
VARCHAR2、NUMBER,后面不能加长度(如VARCHAR2(10))。 - 封装常用逻辑:把那些需要反复使用的计算规则包装起来,能极大提升代码的复用性和可读性。
示例:模拟ABS绝对值函数
我们试着写一个自己的绝对值函数,思路很简单:把数字里的负号去掉。
CREATE OR REPLACE FUNCTION ABS_BAK(P_NUM NUMBER) RETURN NUMBER IS BEGIN RETURN REPLACE(P_NUM, '-'); -- 利用REPLACE函数去掉负号 END;
调用试试:SELECT ABS_BAK(-5) FROM DUAL; 会返回 5。
示例:根据员工编号返回姓名(带错误处理)
再来个业务场景更强的例子,从EMP表查姓名,并考虑员工不存在的情况:
CREATE OR REPLACE FUNCTION GET_EMP_NAME(P_EMPNO NUMBER)
RETURN VARCHAR2
IS
V_NAME VARCHAR2(50);
BEGIN
SELECT ENAME INTO V_NAME FROM EMP WHERE EMPNO = P_EMPNO;
RETURN V_NAME;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN '员工不存在';
WHEN OTHERS THEN
RETURN '查询出错';
END;
这样,在程序里调用GET_EMP_NAME(7369)就能安全地拿到员工姓名了。
三、存储过程(PROCEDURE)
存储过程更像一个“动作”或“流程”。它不关心返回什么结果,只专注于把一系列数据处理步骤打包执行。
语法结构
CREATE OR REPLACE PROCEDURE 过程名(入参名 参数类型) IS 变量声明; BEGIN -- 数据同步、清洗、处理流程... END;
特点
- 没有返回值:这是和函数最直观的区别。
- 封装数据处理流程:特别适合用来做ETL(抽取、转换、加载)、数据同步、定期清理等任务。
示例:同步部门最高薪资
假设我们有个需求,要把每个部门的最高工资同步到另一张汇总表里:
CREATE OR REPLACE PROCEDURE P_SYNC_MAX_SAL IS BEGIN -- 先清空目标表 DELETE FROM H_SAL_EMP; -- 再插入最新的部门最高薪资 INSERT INTO H_SAL_EMP SELECT DEPTNO, MAX(SAL) FROM EMP GROUP BY DEPTNO; COMMIT; -- 记得提交 END;
调用方式
存储过程不能在SQL中直接SELECT,需要在PL/SQL块里调用:
BEGIN P_SYNC_MAX_SAL; END;
示例:带参数的过程
过程也可以带参数,让它更灵活。比如,只同步特定职位的员工数据:
CREATE OR REPLACE PROCEDURE P_SYNC_BY_JOB(C_JOB VARCHAR2) IS BEGIN DELETE FROM EMP_J WHERE JOB = C_JOB; INSERT INTO EMP_J SELECT * FROM EMP WHERE JOB = C_JOB; COMMIT; END;
调用时传入职位即可:BEGIN P_SYNC_BY_JOB('MANAGER'); END;
四、函数 vs 存储过程(面试/考试重点)
这两者经常被拿来比较,搞清楚它们的区别非常重要:
| 对比项 | 函数(FUNCTION) | 存储过程(PROCEDURE) |
|---|---|---|
| 返回值 | 必须有 | 没有 |
| 语法关键字 | FUNCTION | PROCEDURE |
| 使用场景 | 计算并返回一个值 | 封装数据同步、处理流程 |
| 能否在 SQL 中直接调用 | ✅ 可以(如 SELECT 函数名() FROM DUAL) | ❌ 不可以 |
是否必须有 RETURN 语句 | ✅ 是 | ❌ 否(Oracle存储过程不允许使用RETURN返回值) |
简单记:要一个结果就用函数,要执行一个过程就用存储过程。
典型练习题(建议手动敲一遍)
光看不够,动手练练才能真正掌握。下面这几个练习涵盖了循环、函数和过程的核心操作。
1. 循环练习
- 分别使用 FOR 循环和 WHILE 循环,计算 1 到 200 之间所有偶数的和。
- 编写一个程序,打印出 1 到 X(X由用户输入)之间所有的质数。
2. 函数练习
实现一个名为 ELIM 的函数,功能是删除字符串中第一次出现的指定字符。
-- 函数调用示例:
-- ELIM('A-B-C', '-') 应该返回 'AB-C'
-- ELIM('hello world', 'o') 应该返回 'hell world'
CREATE OR REPLACE FUNCTION ELIM(P_STR VARCHAR2, P_CHAR VARCHAR2)
RETURN VARCHAR2
IS
-- 你的逻辑在这里
BEGIN
-- 提示:可以使用 INSTR 找到字符位置,再用 SUBSTR 拼接
RETURN ...;
END;
3. 存储过程练习
先创建一张简单的表:
CREATE TABLE T_NUMBER(ID NUMBER); COMMIT;
然后,创建一个存储过程 P_004(X),它的功能是将所有比 X 小的奇数插入到 T_NUMBER 表中。
CREATE OR REPLACE PROCEDURE p_004(x NUMBER)
IS
BEGIN
-- 清空表格(两种方式任选)
DELETE FROM T_NUMBER;
COMMIT;
-- 或者使用 TRUNCATE(更高效,但操作无法回滚)
-- EXECUTE IMMEDIATE 'TRUNCATE TABLE T_NUMBER';
FOR i IN 1..x-1 LOOP
IF MOD(i,2)=1 THEN
INSERT INTO T_NUMBER(ID) VALUES (i);
END IF;
END LOOP;
COMMIT;
END;
-- 调用存储过程,插入比100小的奇数
BEGIN
p_004(100);
END;
-- 查看结果
SELECT * FROM T_NUMBER ORDER BY ID;
补充:IS可以省略不写吗
这是一个非常具体的语法点,但经常有人搞错。答案是:在Oracle存储过程或函数中,IS(或者它的等价物AS)是必须的,绝对不能省略。
存储过程的基本语法结构:
CREATE OR REPLACE PROCEDURE 过程名(参数)
IS -- 或 AS,必须存在,不能省略
BEGIN
-- 过程体
END;
/
IS 和 AS 的区别:
其实它俩完全等价,用哪个都行,纯粹是个人习惯问题:
-- 使用 IS
CREATE OR REPLACE PROCEDURE p_example(x NUMBER) IS
BEGIN
NULL;
END;
-- 使用 AS(同样正确)
CREATE OR REPLACE PROCEDURE p_example(x NUMBER) AS
BEGIN
NULL;
END;
为什么不能省略?
IS/AS 在语法上有明确的作用:
- 标记声明部分的开始:后面是用来声明变量、游标、类型的地方。
- 分隔头部和主体:它隔开了过程名/参数列表和实际的BEGIN-END执行体。
- 语法规定的必需关键字:Oracle的语法解析器就认这个。
如果省略了,直接就会编译报错:
-- 错误示范(缺少 IS/AS)
CREATE OR REPLACE PROCEDURE p_example(x NUMBER) -- 这里直接跟BEGIN会出错
BEGIN
NULL;
END;
对比其他数据库:
| 数据库 | 语法 | IS/AS 是否必需 |
|---|---|---|
| Oracle | IS 或 AS | 必需 |
| SQL Server | AS | 必需 |
| PostgreSQL | AS | 必需(但写法不同) |
| MySQL | 不需要 | 不需要 |
总结一下:在Oracle里创建存储过程或函数,IS 或 AS 是必须的关键字,不能省略。即使你没有任何变量要声明,也得写上 IS BEGIN ... 这样的结构。
热门专题
热门推荐
Cronos是一条与Crypto com生态紧密关联的EVM兼容链,其原生代币为CRO。本文介绍了Cronos链的核心定位与官网主要功能,包括作为生态入口、区块浏览器和开发者资源中心。同时分析了CRO代币的市值排名影响因素,如生态发展、市场周期和交易所支持。最后为新手提供了关键注意事项,包括区分Cronos链与Crypto com交易所、妥善管理私钥、警惕诈
戴尔笔记本连接手机热点:一篇讲透的实战指南 想把手机流量变成戴尔笔记本的无线网络?这事儿其实比想象中更简单。核心流程不外乎两步:先在手机上打开热点并做好设置,然后在笔记本的Wi-Fi列表里找到它、输入密码。整个过程,依赖的是笔记本内置的无线网卡和通用的Wi-Fi协议,完全无需额外配件。无论是安卓还是
三星显示器连接笔记本电脑,最主流且稳定的方式 想让三星显示器为你的笔记本“添屏加彩”?最主流、也最稳定的方式,还是通过HDMI或USB-C线缆直连,再辅以系统快捷键(比如常见的Fn+F4)快速切换显示模式。好消息是,如今主流的三星显示器普遍配备了HDMI 2 0甚至全功能的USB-C接口,不仅支持最
购买DOT需选择可靠交易平台并完成注册认证。买入时可通过限价单在目标价位挂单,或使用市价单即时成交。卖出时建议分批操作,设置阶梯止盈止损单以管理风险。整个过程需注意资产安全,妥善保管私钥,并关注市场动态做出理性决策。
史密斯热水器清理污垢:一份用户友好的深度清洁指南 给家里的史密斯热水器做一次深度清洁、清一清内胆水垢,这事儿听起来挺专业,但真上手了你会发现,普通用户完全能自己搞定。当然,前提是得把安全规范刻在脑子里。根据品牌官方的售后指南,再结合不少资深维修技师的实操反馈,整套流程其实相当清晰:从断电断水开始,到





