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,一经查实,立即删除!

相关文章

kafka-保姆级配置说明(broker)

一. important ##broker ID,cluster唯一标识,数字类型 ##此值可以不指定,有集群自动创建(由当前集群现有的brokerID 1)。 ##默认值为-1 broker.id5 #broker.id.generation.enabletrue ##zookeeper连接地址 zookeeper.…

推箱子游戏

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

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

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

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

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

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

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

每日一题 417. 太平洋大西洋水流问题

417. 太平洋大西洋水流问题 代码使用队列进行广度搜索&#xff0c;分别遍历太平洋 和大西洋的河流&#xff0c;取交集。 class Solution { public:vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {set<pair<int,int&…

Java设计模式 九 桥接模式 (Bridge Pattern)

桥接模式 (Bridge Pattern) 桥接模式是一种结构型设计模式&#xff0c;它的核心思想是将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。这种模式通过组合而不是继承的方式来扩展功能&#xff0c;从而减少类之间的耦合度。 1. 模式结构 桥接模式的结构包括以下角色&…

USB——cherry 键盘分析

文章目录 cherry USB 键盘分析描述符结构设备描述符配置描述符集合配置描述符接口 1 描述符HID 描述符端点 IN 描述符接口 2 描述符HID 描述符端点 IN 描述符端点 OUT 描述符字符串描述符语言 ID (字符串索引为 0)厂商字符串(字符串索引为 1)产品字符串(字符串索引为 2)HID 报告…

关于自动控制原理中三阶系统瞬态响应与稳定性实验的研究报告

一、引言 1.1 研究背景与意义 自动控制原理作为现代工业生产、航空航天、智能交通等众多领域的关键理论基础&#xff0c;对提高生产效率、提升产品质量以及保障系统安全稳定运行起着举足轻重的作用。在实际应用中&#xff0c;自动控制系统能够根据预设的目标和反馈信息&#…

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

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

vue2和vue3组件之间的通信方式差异

Vue2 vs Vue3 组件通信方法对比 1. 父子组件通信 1.1 Props 传递 Vue2 <!-- 父组件 --> <template><child-component :message"message"></child-component> </template><script> export default {data() {return {message:…

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

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

RedisTemplate和Redisson的使用和区别

文章目录 一. 数据缓存1.1 **为什么要用缓存**1.2 缓存的实现1.3 Redis1.4 Redis 数据结构1.5 实现方式1.6 对比1.7 实现定时预热缓存1.7.1 什么是热缓存1.7.2 什么时候用缓存预热1.7.3 缓存预热带来的问题1.7.4 怎么实现缓存预热1.7.5 预热缓存的注意点1.7.6 缓存预热 - 定时任…

程朱理学基本知识

文章目录 一、儒家兴起和衰落周期二、程颐和程颢三、朱熹四、程朱理学和女性改嫁 理学根本特点就是将儒家的社会、民族及伦理道德和个人生命信仰理念&#xff0c;构成更加完整的概念化及系统化的哲学及信仰体系&#xff0c;并使其逻辑化&#xff0c;心性化、抽象化和真理化。这…

kotlin 简介

Kotlin 是一种现代化、跨平台的编程语言&#xff0c;由 JetBrains 开发&#xff0c;并于 2011 年首次发布。它可以用于多种开发场景&#xff0c;包括 Android 应用开发、后端服务开发、Web 开发&#xff0c;以及跨平台应用开发。 以下是对 Kotlin 的核心介绍&#xff1a; Kotl…

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

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

Spring Boot spring.factories文件详细说明

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

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

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

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

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

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

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