Oracle存储过程语法详解

简介

存储过程是一系列SQL语句的集合,可以封装复杂的逻辑,实现特定的功能,可以提高执行速度和代码的复用性,预先编译后存储在数据库中,可以通过指定存储过程的名称对其进行调用。

本文主要讲解Oracle存储过程语法,包括:总体结构、存储过程声明、参数定义、变量声明、游标声明、行数据类型声明、变量赋值、条件判断、WHILE循环、FOR循环、游标使用、异常捕捉、异常处理、存储过程调用、存储过程代码示例、调用代码示例、调用结果展示

总体结构

一个完整的存储过程结构主要包括:过程声明部分、过程执行部分、异常处理部分,如下所示。

CREATE OR REPLACE PROCEDURE 存储过程名称(参数定义部分)
AS或IS
变量声明部分
BEGIN
  过程执行部分
EXCEPTION
  异常处理部分
END;

样例准备

先准备样例表TESTTABLE01,数据如下图,后续所有代码示例查询的数据都来自这个表。

过程声明部分

声明格式

CREATE OR REPLACE PROCEDURE 存储过程名称(参数定义部分)
AS或IS

其中,【OR REPLACE】表示如果已存在同名的存储过程,则直接替换,即将其覆盖掉,这部分也可以省略,省略后,执行编译时,如果发现同名的存储过程,则会报错提示ORA-00955,如下图。ASIS两种写法效果相同,任选其一。

参数定义

格式:【参数名 输入输出类型 数据类型】,可定义输入或输出的参数,可以不带参数,也可以定义一个或多个参数,多个参数用英文逗号隔开,如下所示。

过程声明和参数定义示例

CREATE OR REPLACE PROCEDURE TESTSP01(
para01 in VARCHAR2,
para02 in INT,
para03 out VARCHAR2
)
AS

para01、para02、para03为自定义的参数名;in或out表示输入或输出参数,输入参数是在调用存储过程时传入的,输出参数是在存储过程内部赋值的,可以输出;VARCHAR2、INT表示参数的数据类型。

说明:【in out】表示该参数既是输入参数也是输出参数。

变量声明

格式:【变量名 数据类型】,变量声明是在BEGIN前面。

可以定义存储过程中需要用到的变量,每个变量用英文分号结尾,如下所示。

var01 VARCHAR2(10);
var02 VARCHAR2(20);
var03 INT;
var04 NUMBER(5);
var05 VARCHAR2(50);

游标声明

格式:【CURSOR  游标名称 IS 查询语句】,游标是内存中用于存储和检索查询结果集的一种数据结构,可以用来遍历的有多条数据的查询结果。

示例:

CURSOR cursor01 IS
SELECT COL01,COL02,COL03
FROM TESTTABLE01
WHERE COL02 IS NOT NULL;

行数据类型

声明游标之后,需要再声明一个行数据类型,用以存储游标中的某一行数据,也可以存储表中的一行数据。

格式:

行变量名称 游标名称%ROWTYPE;

行变量名称 表名称%ROWTYPE;

示例:

row01 cursor01%ROWTYPE;
row02 TESTTABLE01%ROWTYPE;

过程执行部分

变量赋值

格式:【变量名:=变量值】,如下所示,可以将常量、变量等赋值给变量。

  var01:='hello';var02:=var01;var03:=8;var04:=1.8;var05:=var02||' world';

也可以在变量声明的时候直接赋值,如下所示。

var03 INT:=8;
var04 NUMBER(5,2):=1.8;
var05 VARCHAR2(50):='hello world';

还可以把SQL语句的查询结果赋值给变量,格式:【select 字段名或表达式 into 变量名 from ...】,如下所示。

  select count(1) into var03 from TESTTABLE01;select col02 into var01 from TESTTABLE01 where col01='id01';select replace(col02,'value','hello')||' world' into var05 from TESTTABLE01 where col01='id01';

条件判断

格式如下:若条件判断表达式01为真,则执行代码块01,当不满足表达式01时,继续判断,若条件判断表达式02为真,则执行代码块02,若前面的条件都不满足,则执行代码块03。其中ELSIF(注意写法不是ELSEIF)和ELSE部分都可以省略。

IF 条件判断表达式01 THEN

        代码块01

ELSIF 条件判断表达式02 THEN

        代码块02

ELSE

       代码块03

END IF;

示例:

  IF var01 like 'value%' THENvar02:='ret01';ELSIF var03>1 THENvar02:='ret02';ELSEvar02:='ret03';END IF;

WHILE循环

第一种写法如下:如果条件表达式为真,再执行里面的代码块,否则不执行。

WHILE  条件表达式  LOOP
        代码块
END  LOOP ;

第二种写法如下:先执行一次LOOP中的代码块,再判断条件表达式,如果为真,则退出循环,否则,继续执行循环,这种写法与第一种写法的区别在于,不论条件表达式结果如何,LOOP中的代码块会至少执行一次。

LOOP

        代码块

        EXIT WHEN 条件表达式

END LOOP;

FOR循环

格式:每一次执行循环时,会将索引自增一次,从索引范围的最小值开始自增,伴随着每一次循环,直到索引达到索引范围的最大值,就退出循环。

FOR 索引 IN 索引范围 LOOP

        代码块;

END LOOP;

示例:

  -- for循环依次输出1到8FOR i IN 1..8 LOOPvar08:=var08||i;END LOOP;dbms_output.put_line('for循环输出1到8:'||var08);

游标使用

打开游标:【OPEN 游标名称】;

获取游标数据放入行变量:【FETCH 游标名称 INTO 行变量名称】,其中,FETCH在获取当前行数据的同时,还会把游标指针推进到下一条纪录,一般放在循环结构中遍历获取每一条数据。

游标的属性:

游标名称%ISOPEN】:表示游标是否打开,正常情况返回布尔型;
游标名称%FOUND】:表示游标是否获取到数据,正常情况返回布尔型;
游标名称%NOTFOUND】:表示游标是否没有获取到数据,正常情况返回布尔型;
游标名称%ROWCOUNT】:返回游标已经遍历获取的记录数,不是总数量,返回INT型。

示例:

  var061:=cursor01%ISOPEN; -- 游标cursor01是否打开var062:=cursor01%FOUND; -- 游标cursor01是否获取到数据var063:=cursor01%NOTFOUND; -- 游标cursor01是否没有获取到数据var064:=cursor01%ROWCOUNT; -- 返回游标cursor01已经遍历获取的记录数,不是总数量

关闭游标:【CLOSE 游标名称】。

示例1,使用while...loop循环方式读取游标数据:

  -- while...loop循环方式dbms_output.put_line('while...loop循环方式:');OPEN cursor01; -- 打开游标cursor01var061:=cursor01%ISOPEN; -- 游标是否打开var062:=cursor01%FOUND; -- 游标是否获取到数据var063:=cursor01%NOTFOUND; -- 游标是否没有获取到数据FETCH cursor01 INTO row01; -- 从游标cursor01获取行数据赋给行变量row01,并将游标推进到下一行。WHILE cursor01%FOUND LOOP --如果cursor01%FOUND结果为真,则执行while循环BEGINvar_col01 := row01.COL01; -- 获取行变量中的具体字段值赋给左边的变量var_col02 := row01.COL02; -- 获取行变量中的具体字段值赋给左边的变量dbms_output.put_line('获取记录数:'||cursor01%ROWCOUNT); -- 输出内容dbms_output.put_line('当前行数据:'||var_col01||','||var_col02); -- 输出内容FETCH cursor01 INTO row01; -- 从游标cursor01获取行数据赋给行变量row01,并将游标推进到下一行。END; END LOOP;CLOSE cursor01; -- 关闭游标cursor01

示例2,使用loop... exit when...循环方式读取游标数据:

  -- loop... exit when...循环方式dbms_output.put_line('loop... exit when...循环方式:');OPEN cursor01; -- 打开游标cursor01LOOPFETCH cursor01 INTO row01; -- 从游标cursor01获取行数据赋给行变量row01,并将游标推进到下一行。EXIT WHEN cursor01%NOTFOUND; -- 如果cursor01%NOTFOUND结果为真,则退出循环。var_col01 := row01.COL01; -- 获取行变量中的具体字段值赋给左边的变量var_col02 := row01.COL02; -- 获取行变量中的具体字段值赋给左边的变量dbms_output.put_line('获取记录数:'||cursor01%ROWCOUNT); -- 输出内容dbms_output.put_line('当前行数据:'||var_col01||','||var_col02); -- 输出内容END LOOP ;CLOSE cursor01; -- 关闭游标cursor01

示例3,使用for循环方式读取游标数据:

  -- for循环读取游标数据dbms_output.put_line('for循环读取游标数据:');FOR row01 IN cursor01 LOOP -- 遍历游标cursor01获取数据赋给行变量row01var_col01 := row01.COL01; -- 获取行变量中的具体字段值赋给左边的变量var_col02 := row01.COL02; -- 获取行变量中的具体字段值赋给左边的变量dbms_output.put_line('获取记录数:'||cursor01%ROWCOUNT); -- 输出内容dbms_output.put_line('当前行数据:'||var_col01||','||var_col02); -- 输出内容END LOOP;

异常处理部分

异常捕捉

格式:EXCEPTION可以捕捉到存储过程执行中遇到的异常,WHEN后面是具体的异常名称,捕捉到具体异常后,就会执行对应WHEN下面的异常处理代码块,如果捕捉到的异常和前面任何一个WHEN后面的异常名称都不匹配,则直接执行【WHEN OTHERS THEN】下面的异常处理代码。

EXCEPTION
  WHEN 异常01 THEN 
     异常处理代码块01
  WHEN 异常02 THEN 

     异常处理代码块02

  ......
  WHEN OTHERS THEN
    异常处理代码块n

异常处理部分也可以只有OTHERS部分,格式如下,捕捉到任何异常都会跳转到OTHERS对应的异常处理代码块。

EXCEPTION
  WHEN OTHERS THEN
    异常处理代码块

异常处理

SQLCODE:获取错误代码,

SQLERRM:获取具体的错误信息,

ROLLBACK:回滚事务。

异常处理示例:

EXCEPTIONWHEN NO_DATA_FOUND THEN dbms_output.put_line('未查询到数据!');WHEN CURSOR_ALREADY_OPEN THEN dbms_output.put_line('游标已经打开!');WHEN OTHERS THENdbms_output.put_line(SQLCODE); -- 输出错误代码dbms_output.put_line(SQLERRM); -- 输出错误信息

调用存储过程

调用命令格式

如果存储过程不带参数,调用格式如下。

call 存储过程名称();

如果存储过程只带输入参数,参数值用英文逗号隔开,传入的值要和存储过程定义的参数的顺序和类型保持一致,调用格式如下。

call 存储过程名称(参数值1,参数值2,...);

如果存储过程带输出参数,比如某个存储过程有三个参数,前两个为输入参数,第三个为输出参数,调用格式如下,需要先定义一个变量用来接收输出参数值,数据类型要和输出参数相同。

BEGIN
  DECLARE
    变量名01 数据类型;
  BEGIN
    存储过程名称(传入值01,传入值02,变量名01);
  END;
END;

完整存储过程示例

-- 存储过程声明,可以带参数,也可以不带参数
CREATE OR REPLACE PROCEDURE TESTSP01(
para01 in VARCHAR2,
para02 in INT,
para03 out VARCHAR2
)AS-- 变量定义,可以在变量定义时赋值。
var01 VARCHAR2(10);
var02 VARCHAR2(20);
var03 INT:=0;
var04 NUMBER(5,2):=8.88;
var05 VARCHAR2(50):='initvalue';
var06 INT;
var061 BOOLEAN;
var062 BOOLEAN;
var063 BOOLEAN;
var07 VARCHAR2(30);
var08 VARCHAR2(20):='';
var_col01 VARCHAR2(20);
var_col02 VARCHAR2(20);-- 游标声明
CURSOR cursor01 IS
SELECT COL01,COL02,COL03
FROM TESTTABLE01
WHERE COL02 IS NOT NULL;-- 行变量声明
row01 cursor01%ROWTYPE;
row02 TESTTABLE01%ROWTYPE;BEGIN -- 过程执行部分-- 变量赋值,可以将常量或变量赋值给变量dbms_output.put_line('变量赋值示例:');var01:='hello';var02:=var01;var03:=8;var04:=1.8;dbms_output.put_line('var01:'||var01||','||'var02:'||var02||','||'var03:'||var03||','||'var04:'||var04);-- 通过sql查询给变量赋值select col02 into var05 from TESTTABLE01 where col01='id01';select count(1) into var06 from TESTTABLE01;select replace(col02,'value','hello')||' world' into var07 from TESTTABLE01 where col01='id01';dbms_output.put_line('var05:'||var05||','||'var06:'||var06||','||'var07:'||var07);-- IF判断示例dbms_output.put_line('IF判断示例:');IF para01 like 'value%' THENdbms_output.put_line('IF判断满足第一个分支');ELSIF para02>1 THENdbms_output.put_line('IF判断满足第二个分支');ELSEdbms_output.put_line('IF判断满足第三个分支');END IF;-- while...loop循环方式读取游标数据dbms_output.put_line('while...loop循环方式读取游标数据:');OPEN cursor01; -- 打开游标cursor01var061:=cursor01%ISOPEN; -- 游标cursor01是否打开  var062:=cursor01%FOUND; -- 游标cursor01是否获取到数据var063:=cursor01%NOTFOUND; -- 游标cursor01是否没有获取到数据FETCH cursor01 INTO row01; -- 从游标cursor01获取行数据赋给行变量row01,并将游标推进到下一行。WHILE cursor01%FOUND LOOP --如果cursor01%FOUND结果为真,则执行while循环BEGINvar_col01 := row01.COL01; -- 获取行变量中的具体字段值赋给左边的变量var_col02 := row01.COL02; -- 获取行变量中的具体字段值赋给左边的变量dbms_output.put_line('获取记录数:'||cursor01%ROWCOUNT); -- 输出内容dbms_output.put_line('当前行数据:'||var_col01||','||var_col02); -- 输出内容FETCH cursor01 INTO row01; -- 从游标cursor01获取行数据赋给行变量row01,并将游标推进到下一行。END; END LOOP;CLOSE cursor01; -- 关闭游标cursor01-- loop... exit when...循环方式读取游标数据dbms_output.put_line('loop... exit when...循环方式读取游标数据:');OPEN cursor01; -- 打开游标cursor01LOOPFETCH cursor01 INTO row01; -- 从游标cursor01获取行数据赋给行变量row01,并将游标推进到下一行。EXIT WHEN cursor01%NOTFOUND; -- 如果cursor01%NOTFOUND结果为真,则退出循环。var_col01 := row01.COL01; -- 获取行变量中的具体字段值赋给左边的变量var_col02 := row01.COL02; -- 获取行变量中的具体字段值赋给左边的变量dbms_output.put_line('获取记录数:'||cursor01%ROWCOUNT); -- 输出内容dbms_output.put_line('当前行数据:'||var_col01||','||var_col02); -- 输出内容END LOOP ;CLOSE cursor01; -- 关闭游标cursor01-- for循环依次输出1到8FOR i IN 1..8 LOOPvar08:=var08||i;END LOOP;dbms_output.put_line('for循环输出1到8:'||var08);-- for循环读取游标数据dbms_output.put_line('for循环读取游标数据:');FOR row01 IN cursor01 LOOP -- 遍历游标cursor01获取数据赋给行变量row01var_col01 := row01.COL01; -- 获取行变量中的具体字段值赋给左边的变量var_col02 := row01.COL02; -- 获取行变量中的具体字段值赋给左边的变量dbms_output.put_line('获取记录数:'||cursor01%ROWCOUNT); -- 输出内容dbms_output.put_line('当前行数据:'||var_col01||','||var_col02); -- 输出内容END LOOP;--给输出参数赋值para03:='存储过程执行成功!';EXCEPTION -- 异常处理部分WHEN NO_DATA_FOUND THEN dbms_output.put_line('未查询到数据!');WHEN CURSOR_ALREADY_OPEN THEN dbms_output.put_line('游标已经打开!');WHEN OTHERS THENdbms_output.put_line(SQLCODE); -- 输出错误代码dbms_output.put_line(SQLERRM); -- 输出错误信息
END;

调用存储过程示例

BEGINDECLARE-- 定义变量接收输出参数值,数据类型要和输出参数相同outpara VARCHAR2(50); BEGIN-- 调用存储过程,给输入参数赋值,将事先定义的变量传给输出参数。TESTSP01('value_in',8,outpara); -- 打印输出参数dbms_output.put_line('输出参数值:'||outpara); END;
END;

调用输出结果展示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/893593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推箱子游戏

java小游戏2 一游戏介绍 二图像准备 墙、箱子、人、箱子目的地,人左边、人右边、人上边、人下边 三结构准备 地图是什么,我们把地图想象成一个网格,每个格子就是工人每次移动的步长,也是箱子移动的距离,设置一个二维数…

如何分辨ddos攻击和cc攻击?

DDoS(分布式拒绝服务)攻击和 CC(Challenge Collapsar)攻击都属于网络攻击手段,主要通过消耗目标服务器资源使其无法正常提供服务,但它们在攻击原理、攻击特征等方面存在区别: 攻击原理 DDoS 攻…

期权帮|如何利用股指期货进行对冲套利?

锦鲤三三每日分享期权知识,帮助期权新手及时有效地掌握即市趋势与新资讯! 如何利用股指期货进行对冲套利? 对冲就是通过股指期货来平衡投资组合的风险。它分为正向与反向两种策略: (1)正向对冲&#xff…

软件质量与测试报告5-压力测试 JMeter 与 Badboy

A.百度搜索引擎压力测试 通过在Badboy下执行如下的测试场景来生成压力测试的脚本: a) 在Badboy的地址栏里面输入www.baidu.com,回车; b) 在右下区域打开的百度的主页上输入搜索关键字JMeter,回车; c) 在…

Mybatis多条件查询:Map传参与对象传参解析

Mybatis 多条件查询常见且关键,本文探讨两种方法——Map 传参和 Java Bean 对象传参,展示用法及区别,总结应用场景和优缺点。 1. Map传参方式 原理:Mybatis允许我们通过一个Map对象来传递动态SQL中的参数。Map的键对应于SQL语句中…

wangEditor富文本编辑器,Laravel上传图片配置和使用

文章目录 前言步骤1. 构造好前端模版2. 搭建后端存储3. 调试 前言 由于最近写项目需要使用富文本编辑器,使用的是VUE3.0版本所以很多不兼容,实际测试以后推荐使用wangEditor 步骤 构造好前端模版搭建后端存储调试 1. 构造好前端模版 安装模版 模版安…

three.js+WebGL踩坑经验合集(2):3D场景被相机裁切后,被裁切的部分依然可以被鼠标碰撞检测得到(射线检测)

three.js内置了Raycaster类实现鼠标的碰撞检测,用它可以实现3D物体的鼠标点击,移入移出,触屏检测一类的业务功能。 该功能虽然强大,但同事们普遍反映不是那么好用,因为它不像其它配套了可视编辑的3D引擎一样&#xff…

Spring Boot spring.factories文件详细说明

优质博文:IT-BLOG-CN 前言:经常看到 spring.factories 文件,却没有对它进行深入的了解和分析,今天我们就一起揭开面纱看看它的内在。 spring.factories 文件是 Spring Boot 自动配置机制的核心部分之一。它位于每个 Spring Boo…

从前端视角看设计模式之行为型模式篇

上篇我们介绍了 设计模式之结构型模式篇,接下来介绍设计模式之行为型模式篇 责任链模式 责任链模式允许将请求沿着一条链传递,直到有一个对象处理它为止。每个处理者都有机会处理该请求,或者将其传递给链中的下一个处理者,每个处…

[2025分类时序异常检测指标R-AUC与VUS]

梳理了一下分类中常见的指标,这些指标与时序异常检测中新提出的A-RUC与VUS之间的关系 真正例(True Positive,TP): 被正确识别为正样本的数量。真负例(True Negative,TN): 被正确识别为负样本的数量。假正例(False Positive ,FP): 被错误识为正样本数量假负例(Fals…

Unity中实现伤害跳字效果(简单好抄)

第一步骤安装并导入Dotween插件(也可以不用导入之后直接下载我的安装包) 官网DOTween - 下载 第二步: 制作跳字预制体 建议把最佳适应打开,这样就不怕数字太大显示不全了。 第三步:创建一个空对象并编写脚本JumpNumbe…

考研机试:学分绩点

描述 北京大学对本科生的成绩施行平均学分绩点制(GPA)。 既将学生的实际考分根据不同的学科的不同学分按一定的公式进行计算。 公式如下: 一门课程的学分绩点 该课绩点 该课学分 总评绩点 所有学科学分绩点之和 / 所有课程学分之和 …

【玩转全栈】----YOLO8训练自己的模型并应用

继上篇: 【玩转全栈】---基于YOLO8的图片、视频目标检测-CSDN博客 相信大家已经可以训练一些图片和视频了,接下来我将为大家介绍如何训练自己的特定模型,并用其进行检测 目录 准备数据 图片数据 标识数据 配置文件 运行 测试训练结果 存在的问…

OpenCV文字绘制支持中文显示

OpenCV版本:4.4 IDE:VS2019 功能描述 OpenCV绘制文本的函数putText()不支持中文的显示,网上很多方法推荐的都是使用FreeType来支持,FreeType是什么呢?FreeType的官网上有介绍 FreeType官网 https://www.freetype.or…

我谈《概率论与数理统计》的知识体系

学习《概率论与数理统计》二十多年后,在廖老师的指导下,才厘清了各章之间的关系。首先,这是两个学科综合的一门课程,这一门课程中还有术语冲突的问题。这一门课程一条线两个分支,脉络很清晰。 概率论与统计学 概率论…

ElasticSearch JavaRestClient查询之快速入门

文章目录 查询操作流程概述构建并发起请求1. 创建请求对象2. 设置请求体3. 发送请求 查询结果的解析1. 解析结果结构2. 获取总条数3. 获取命中的数据 完整示例代码总结 查询操作流程概述 Elasticsearch 查询操作大致可以分为两个部分: 构建并发起请求:…

Quartus:开发使用及 Tips 总结

Quartus是Altera(现已被Intel收购)推出的一款针对其FPGA产品的综合性开发环境,用于设计、仿真和调试数字电路。以下是使用Quartus的一些总结和技巧(Tips),帮助更高效地进行FPGA项目开发: 这里写目录标题 使用总结TIPS…

elementUI Table组件实现表头吸顶效果

需求描述 当 table 内容过多的时候,页面上滑滚动,表头的信息也会随着被遮挡,无法将表头信息和表格内容对应起来,需要进行表头吸顶 开始编码💪 环境:vue2.6、element UI step1: 给el-table__h…

用于牙科的多任务视频增强

Multi-task Video Enhancement for Dental Interventions 2022 miccai Abstract 微型照相机牢牢地固定在牙科手机上,这样牙医就可以持续地监测保守牙科手术的进展情况。但视频辅助牙科干预中的视频增强减轻了低光、噪音、模糊和相机握手等降低视觉舒适度的问题。…

Vue3轮播图左右联动

1、轮播图部分,右边鼠标移入,左边对应展示轮播图 可以在swiper 官网 Swiper中文网-轮播图幻灯片js插件,H5页面前端开发 选择vue中使用swiper npm i swiper 左右两边的联动:左边的轮播图和右边的小的列表他们的列表组成结构是一样的&#…