转载至:

https://www.2cto.com/database/201610/559389.htm

1.什么是oracle存储过程

存储过程和函数也是一种PL/SQL块,是存入数据库的PL/SQL块。但存储过程和函数不同于已经介绍过的PL/SQL程序,我们通常把PL/SQL程序称为无名块,而存储过程和函数是以命名的方式存储于数据库中的。和PL/SQL程序相比,存储过程有很多优点,具体归纳:

1. 存储过程和函数以命名的数据库对象形式存储于数据库当中。存储在数据库中的优点是很明显的,因为代码不保存在本地,用户可以在任何客户机上登录到数据库,并调用或修改代码。

2. 存储过程和函数可由数据库提供安全保证,要想使用存储过程和函数,需要有存储过程和函数的所有者的授权,只有被授权的用户或创建者本身才能执行存储过程或调用函数。

3. 存储过程和函数的信息是写入数据字典的,所以存储过程可以看作是一个公用模块,用户编写的PL/SQL程序或其他存储过程都可以调用它(但存储过程和函数不能调用PL/SQL程序)。一个重复使用的功能,可以设计成为存储过程。

4. 像其他高级语言的过程和函数一样,可以传递参数给存储过程或函数,参数的传递也有多种方式。存储过程可以有返回值,也可以没有返回值,存储过程的返回值必须通过参数带回;函数有一定的数据类型,像其他的标准函数一样,我们可以通过对函数名的调用返回函数值。

5. 存储过程和函数需要进行编译,以排除语法错误,只有编译通过才能调用。

2.如何创建和删除存储过程

2.1.创建存储过程的语法

CREATE [OR REPLACE] PROCEDURE 存储过程名[(参数[IN|OUT|IN OUT] 数据类型...)]

{AS|IS}

[说明部分]

BEGIN

可执行部分

[EXCEPTION

错误处理部分]

END [过程名];

其中:

可选关键字OR REPLACE 表示如果存储过程已经存在,则用新的存储过程覆盖,通常用于存储过程的重建。

参数部分用于定义多个参数(如果没有参数,就可以省略)。参数有三种形式:IN、OUT和IN OUT。如果没有指明参数的形式,则默认为IN。 关键字AS也可以写成IS,后跟过程的说明部分,可以在此定义过程的局部变量。(注意:大小写不敏感)。

简单的存储过程示例:

create or replace procedure hello_world as

say_hi varchar2(20);

begin

say_hi := 'Hello World!';

dbms_output.put_line(say_hi);

end;

2.2 删除存储过程

语法:

DROP PROCEDURE 存储过程名;

如:drop procedure hello_world;

3.存储过程的查看

可以通过对数据字典的访问来查询存储过程或函数的有关信息,如果要查询当前用户的存储过程或函数的源代码,可以通过对USER_SOURCE数据字典视图的查询得到。

3.1查看存储过程的脚本

如查询存储过程hello_world的脚本

Select text from user_source where name = ‘HELLO_WORLD’;

(这里的过程名必须大写)

3.2 查看存储过程的状态

如:select status from user_objects where object_name = ‘HELLO_WORLD’;

说明:VALID表示该存储过程有效(即通过编译),INVALID表示存储过程无效或需要重新编译。当Oracle调用一个无效的存储过程或函数时,首先试图对其进行编译,如果编译成功则将状态置成VALID并执行,否则给出错误信息。

当一个存储过程编译成功,状态变为VALID,会不会在某些情况下变成INVALID。结论是完全可能的。比如一个存储过程中包含对表的查询,如果表被修改或删除,存储过程就会变成无效INVALID。所以要注意存储过程和函数对其他对象的依赖关系。

4.存储过程参数说明

三种形式的参数

1. IN 定义一个输入参数变量,用于传递参数给存储过程

2. OUT 定义一个输出参数变量,用于从存储过程获取数据

3. IN OUT 定义一个输入、输出参数变量,兼有以上两者的功能

参数的定义形式和作用如下:

4.1 IN参数

语法:参数名 IN 数据类型 DEFAULT 值;

定义一个输入参数变量,用于传递参数给存储过程。在调用存储过程时,主程序的实际参数可以是常量、有值变量或表达式等。DEFAULT 关键字为可选项,用来设定参数的默认值。如果在调用存储过程时不指明参数,则参数变量取默认值。在存储过程中,输入变量接收主程序传递的值,但不能对其进行赋值。

4.2 OUT参数

语法:参数名 OUT 数据类型;

定义一个输出参数变量,用于从存储过程获取数据,即变量从存储过程中返回值给主程序。

在调用存储过程时,主程序的实际参数只能是一个变量,而不能是常量或表达式。在存储过程中,参数变量只能被赋值而不能将其用于赋值,在存储过程中必须给输出变量至少赋值一次。

4.3 IN OUT参数

语法:参数名 IN OUT 数据类型 DEFAULT 值;

定义一个输入、输出参数变量,兼有以上两者的功能。在调用存储过程时,主程序的实际参数只能是一个变量,而不能是常量或表达式。DEFAULT 关键字为可选项,用来设定参数的默认值。在存储过程中,变量接收主程序传递的值,同时可以参加赋值运算,也可以对其进行赋值。在存储过程中必须给变量至少赋值一次。

示例:

create or replace procedure say_hi(to_whom in varchar2 default '张三', who out varchar2)

as

who_name varchar(20);

begin

who_name := '李四';

who := who_name;

dbms_output.put_line('Say Hi to '||to_whom);

end;

create or replace procedure invoke_say_hi

as

who varchar2(20);

whom varchar2(20);

begin

whom := '小明';

say_hi(whom, who);

say_hi(who => who);

dbms_output.put_line(who||'say hi to '||whom);

end;

参数的值由调用者传递,传递的参数的个数、类型和顺序应该和定义的一致。如果顺序不一致,可以采用以下调用方法:

过程名(参数名 => 参数的值,参数名 => 参数的值, ~~~~~);

如上面的示例: say_hi(who => who); =>运算符左侧是参数名,右侧是参数表达式.

存储过程参数宽度:

无法在存储过程的定义中指定存储参数的宽度,也就导致了我们无法在存储过程中控制传入变量的宽度。这个宽度是完全由外部传入时决定的。

5.游标

5.1 普通游标

游标定义: cursor [游标名] is [sql语句]

普通游标把整个查询已经写死,调用时不可以作任何改变

注意:这里的is不能用as代替

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
create or replace procedure cursor_sample
 
as
 
user_name varchar2(20);
 
user_id varchar2(20);
 
cursor select_user is select t.user_name, t.user_id from t_user t;
 
begin
 
open select_user;
 
loop
 
fetch select_user into user_name, user_id;
 
exit when select_user%notfound;
 
dbms_output.put_line('UserId:'||user_id||' UserName: '||user_name);
 
end loop;
 
close select_user;
 
end;

5.2动态查询游标

动态查询游标,查询条件的参数由变量决定。

例:

create or replace procedure cursor_sample2

as

vuser_id varchar2(20);

vuser_name varchar2(20);

cursor get_user_by_id is select t.user_id, t.user_name from t_user t where t.user_id = vuser_id;

begin

vuser_id := 'root2';

open get_user_by_id;

loop

fetch get_user_by_id into vuser_id, vuser_name;

exit when get_user_by_id%notfound;

dbms_output.put_line('UserName:'||vuser_name||' UserId:'||vuser_id);

end loop;

close get_user_by_id;

end;

5.3游标变量

先定义了一个引用游标类型,然后再声明了一个游标变量. 然后再用open for 来打开一个查询。需要注意的是它可以多次使用,用来打开不同的查询。

示例:

create or replace procedure cursor_sample3

as

vuser_name varchar2(20);

vuser_id varchar2(20);

type cursor_type is ref cursor;

select_user cursor_type;

begin

open select_user for select t.user_name, t.user_id from t_user t;

loop

fetch select_user into vuser_name, vuser_id;

exit when select_user%notfound;

dbms_output.put_line('UserName:'||vuser_name||' ||UserId:'||vuser_id);

end loop;

close select_user;

dbms_output.put_line('***********************************************');

dbms_output.put_line('****************第二次使用游标**********************');

open select_user for select t.user_name, t.user_id from t_user t where t.user_id = 'root2';

loop

fetch select_user into vuser_name, vuser_id;

exit when select_user%notfound;

dbms_output.put_line('UserName:'||vuser_name||' ||UserId:'||vuser_id);

end loop;

close select_user;

end;

5.4游标循环的方法

(1)游标的%found和%notfound属性。

能从游标中取出记录,得到的结果为%found,取不到记录为%notfound。在打开一个游标之后,马上检查它的%found或%notfound属性,它得到的结果即不是true也不是false.而是null.必须执行一条fetch语句后,这些属性才有值。

三种循环方法

5.4.1【Loop循环】

loop

fetch select_user into vuser_name, vuser_id;

exit when select_user%notfound;

【Do something】;

end loop;

close select_user;

5.4.2【while循环】

fetch select_user into vuser_name, vuser_id;

while select_user%found loop

dbms_output.put_line('UserName:'||vuser_name||' ||UserId:'||vuser_id);

fetch select_user into vuser_name, vuser_id;

end loop;

close select_user;

说明:我们知道了一个游标打开后,必须执行一次fetch语句,游标的属性才会起作用。所以使用while 循环时,就需要在循环之前进行一次fetch动作。

而且数据处理动作必须放在循环体内的fetch方法之前。循环体内的fetch方法要放在最后。否则就会多处理一次。这一点也要非常的小心。

使用while来循环处理游标是最复杂的方法。

5.4.3【for循环】

create or replace procedure cursor_sample4

as

vuser_name varchar2(20);

vuser_id varchar2(20);

cursor select_user is select t.user_name, t.user_id from t_user t;

begin

for v_pos in select_user loop

vuser_name := v_pos.user_name;

vuser_id := v_pos.user_id;

dbms_output.put_line('UserName:'||vuser_name||'UserId'||vuser_id);

end loop;

end;

说明:for循环是比较简单实用的方法。

首先,它会自动open和close游标。解决了你忘记打开或关闭游标的烦恼。

其次,自动定义了一个记录类型及声明该类型的变量,并自动fetch数据到这个变量中。 我们需要注意v_pos 这个变量无需要在循环外进行声明,无需要为其指定数据类型。 它应该是一个记录类型,具体的结构是由游标决定的。这个变量的作用域仅仅是在循环体内。 把v_pos看作一个记录变量就可以了,如果要获得某一个值就像调用记录一样就可以了。 如v_pos.user_name由此可见,for循环是用来循环游标的最好方法。高效,简洁,安全。

6.异常处理

语法:exception when [异常名] then [dosomething] …

When others then [dosomething];

示例:

create or replace procedure exception_sample

as

vuser_name varchar2(20);

vuser_id varchar2(20);

vsqlcode varchar2(10);

vsqlerrm varchar2(1000);

begin

select t.user_name, t.user_id into vuser_name, vuser_id from t_user t where 1 = 0;

exception

when others

then

vsqlcode := sqlcode;

vsqlerrm := sqlerrm;

dbms_output.put_line('Exception, code:'||vsqlcode||' Error message:'||sqlerrm);

end;

另外:若在代码中需要抛出异常时,用raise+异常名

如以下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
create or replace procedure exception_sample2
 
as
 
vuser_name varchar2(20);
 
vuser_id varchar2(20);
 
yourexception exception; --自定义异常
 
cursor select_user is select t.user_name, t.user_id from t_user t;
 
begin
 
open select_user;
 
loop
 
fetch select_user into vuser_name, vuser_id;
 
exit when select_user%notfound;
 
if vuser_id = 'root2' then
 
raise yourexception; --抛出异常
 
end if;
 
end loop;
 
exception
 
when yourexception then
 
dbms_output.put_line('人品异常');
 
when others then
 
dbms_output.put_line(sqlcode||sqlerrm);
 
end;

已经命名的异常

命名的系统异常 产生原因

ACCESS_INTO_NULL 未定义对象

CASE_NOT_FOUND CASE 中若未包含相应的 WHEN ,并且没有设置

ELSE 时

COLLECTION_IS_NULL 集合元素未初始化

CURSER_ALREADY_OPEN 游标已经打开

DUP_VAL_ON_INDEX 唯一索引对应的列上有重复的值

INVALID_CURSOR 在不合法的游标上进行操作

INVALID_NUMBER 内嵌的 SQL 语句不能将字符转换为数字

NO_DATA_FOUND 使用 select into 未返回行,或应用索引表未初始化的

TOO_MANY_ROWS 执行 select into 时,结果集超过一行

ZERO_DIVIDE 除数为 0

SUBSCRIPT_BEYOND_COUNT 元素下标超过嵌套表或 VARRAY 的最大值

SUBSCRIPT_OUTSIDE_LIMIT 使用嵌套表或 VARRAY 时,将下标指定为负数

VALUE_ERROR 赋值时,变量长度不足以容纳实际数据

LOGIN_DENIED PL/SQL 应用程序连接到 oracle 数据库时,提供了不

正确的用户名或密码

NOT_LOGGED_ON PL/SQL 应用程序在没有连接 oralce 数据库的情况下

访问数据

PROGRAM_ERROR PL/SQL 内部问题,可能需要重装数据字典& pl./SQL

系统包

ROWTYPE_MISMATCH 宿主游标变量与 PL/SQL 游标变量的返回类型不兼容

SELF_IS_NULL 使用对象类型时,在 null 对象上调用对象方法

STORAGE_ERROR 运行 PL/SQL 时,超出内存空间

SYS_INVALID_ID 无效的 ROWID 字符串

TIMEOUT_ON_RESOURCE Oracle 在等待资源时超时

7.过程内部块

我们知道了存储过程的结构,语句块由begin开始,以end结束。这些块是可以嵌套。在语句块中可以嵌套任何以下的块:

Declare … begin … exception … end;

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
create or replace procedure innerblock_sample
 
as
 
vuser_name varchar2(20);
 
vuser_id varchar2(20);
 
cursor select_user is select t.user_name, t.user_id from t_user t;
 
begin
 
open select_user;
 
loop
 
fetch select_user into vuser_name, vuser_id;
 
exit when select_user%notfound;
 
dbms_output.put_line('UserName:'||vuser_name||'UserId'||vuser_id);
 
end loop;
 
close select_user;
 
declare
 
vuser_level varchar2(20);
 
cursor get_level is select t.user_level from t_user t;
 
begin
 
open get_level;
 
loop
 
fetch get_level into vuser_level;
 
exit when get_level%notfound;
 
dbms_output.put_line('UserLevel:'||vuser_level);
 
end loop;
 
close get_level;
 
exception when others then
 
dbms_output.put_line(sqlcode||sqlerrm);
 
end;
 
exception when others then
 
dbms_output.put_line(sqlcode||sqlerrm);
 
end;

 

 

oracle储存过程学习笔记的更多相关文章

  1. 基于STM32的USB枚举过程学习笔记

    源:基于STM32的USB枚举过程学习笔记 基于STM32的USB枚举过程学习笔记(一) 基于STM32的USB枚举过程学习笔记(二) 基于STM32的USB枚举过程学习笔记(三) 基于STM32的U ...

  2. Oracle教程之学习笔记

    Oracle教程之学习笔记... ----------------------------------- Oracle教程:---学习笔记: ============================= ...

  3. 转:oracle物化视图学习笔记

    最近学习了一下物化视图,正好经理不在,把学习结果贴出来供大家一起研究一下吧. 先看一下物化视图的大概含义吧,感觉baidu的定义还不错 物化视图,它是用于预先计算并保存表连接或聚集等耗时较多的操作的结 ...

  4. oracle储存过程,job,视图,触发器(记性不好,写个例子自己记)

    存储过程 create or replace procedure TestPro(Descerr out varchar2 ) is begin select * from test; excepti ...

  5. Oracle索引知识学习笔记

    目录 一.Oracle索引简介 1.1 索引分类 1.2 索引数据结构 1.3 索引特性 1.4 索引使用注意要点 1.5.索引的缺点 1.6.索引失效 二.索引分类介绍 2.1.位图索引 1.2.函 ...

  6. Oracle经典教程学习笔记

    Oracle学习 1.为表创建约束:alter table 表名 add constraint 约束名 约束内容 演示样例:alter bable infos add constraint UN_ST ...

  7. 20135202闫佳歆--week 8 进程的切换和系统的一般执行过程--学习笔记

    此为个人笔记存档 week 8 进程的切换和系统的一般执行过程 一.进程调度与进程切换 1.不同的进程有不同的调度需求 第一种分类: I/O密集型(I/O-bound) 频繁的进行I/O 通常会花费很 ...

  8. 基于STM32的USB枚举过程学习笔记(转)

    之前使用ST官方的库以及网络的资料,完成了使用USB HID类进行STM32和PC机的通讯.由于其他原因并没有深入的分析,虽然实现了功能,但是关于USB设备的枚举,以及具体的通讯方式都没有清晰的概念, ...

  9. Android APK安装过程学习笔记

    1.什么是APK APK,即Android Package,Android安装包.不同平台的安装文件格式都不同,类似于Windows的安装包是二进制的exe格式,Mac的安装包是dmg格式.APK可以 ...

随机推荐

  1. C语言学习及应用笔记之七:C语言中的回调函数及使用方式

    我们在使用C语言实现相对复杂的软件开发时,经常会碰到使用回调函数的问题.但是回调函数的理解和使用却不是一件简单的事,在本篇我们根据我们个人的理解和应用经验对回调函数做简要的分析. 1.什么是回调函数 ...

  2. 源码安装zabbix遇到的报错集锦

    报错1:checking for mysql_config... configure: error: MySQL library not found 解决办法:查找mysql_config #find ...

  3. C# .Net List<T>中Remove()、RemoveAt()、RemoveRange()、RemoveAll()的区别,List<T>删除汇总

    在List<T>中删除主要有Remove().RemoveAt().RemoveRange().RemoveAll()这几个方法.下面一一介绍使用方法和注意点. 我们以List<st ...

  4. 寻找符合条件的最短子字符串——SLIDING WINDOW

    简介 用一个可伸缩的窗口遍历字符串,时间复杂度大致为O(n).适用于“寻找符合某条件的最小子字符串”题型. 题目 链接 求某字符串T中含有某字符串S的所有字符的最小子字符串.如果不存在则返回" ...

  5. 将LibreOffice文档转换为豆瓣日记

    豆瓣日记的编辑器一直以来都只支持纯文本的,因此无法将原先在LibreOffice中写的带有简单格式的文章导出.由于我在豆瓣主要写一些随笔性的内容,所以它们在LibreOffice中排版时也并未用到什么 ...

  6. 安装酷痞到IIS7.x共用80端口Windows(64位)系统下运行多个酷痞

    需求: 1.酷痞直接运行的模式是自宿主运行.由于win系统一般都由iis提供多个网站服务,并首先占用了80端口,如果想酷痞可以直接通过主机头和iis共用80端口会出现这种运行模式的需求. 以下是实现方 ...

  7. 【Java】 剑指offer(11) 矩阵中的路径

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字 ...

  8. pandas 必背函数操作

    1.五个常用属性 index,columns,shape,values,dtypes2.常用函数:set_index,reset_index,del df['column_name'],pd.read ...

  9. 设备唯一标识方法(Unique Identifier):如何在Windows系统上获取设备的唯一标识 zz

    原文地址:http://www.vonwei.com/post/UniqueDeviceIDforWindows.html 唯一的标识一个设备是一个基本功能,可以拥有很多应用场景,比如软件授权(如何保 ...

  10. 【IT小常识】如何将IE手动升级或降级

    我们从浏览器任意下载一个我们需要安装的IE版本.可能部分电脑的IE版本不是微软正版的IE版本,所以无法通过更新来获取我们想要的IE版本. 下面,详细的讲一下如何如何手动升级IE或者吧IE降级. 一. ...