Oracle存储过程常用技巧,2024Java笔试题总结

create or replace procedure proc1(

p_para1 varchar2,

p_para2 out varchar2,

p_para3 in out varchar2

)as

v_name varchar2(20);

begin

v_name := ‘素小暖’;

p_para3 := v_name;

dbms_output.put_line(‘p_para3:’||p_para3);

end;

上面就是一个最简单的存储过程,一个存储过程大概分为这么几个部分:

创建语句:create or replace procedure 存储过程名

如果没有or replace语句,则仅仅是新建一个存储过程,如果系统存在该存储过程,则会报错。create or replace procedure如果系统中没有此存储过程就新建一个,如果系统中有此存储过程则把原来删除掉,重新创建一个存储过程。

存储过程名定义:包括存储过程名和参数列表。参数名和参数类型。参数名不能重复, 参数传递方式:IN, OUT, IN OUT

IN 表示输入参数,按值传递方式。

OUT 表示输出参数,可以理解为按引用传递方式。可以作为存储过程的输出结果,供外部调用者使用。

IN OUT 即可作输入参数,也可作输出参数。

参数的数据类型只需要指明类型名即可,不需要指定宽度。

参数的宽度由外部调用者决定。

过程可以有参数,也可以没有参数

变量声明块:紧跟着的as (is )关键字,可以理解为pl/sql的declare关键字,用于声明变量。

变量声明块用于声明该存储过程需要用到的变量,它的作用域为该存储过程。另外这里声明的变量必须指定宽度。遵循PL/SQL的变量声明规范。

过程语句块:从begin 关键字开始为过程的语句块。存储过程的具体逻辑在这里来实现。

异常处理块:关键字为exception ,为处理语句产生的异常。该部分为可选

结束块:由end关键字结果。

1.2 存储过程的参数传递方式

存储过程的参数传递有三种方式:IN,OUT,IN OUT .

IN 按值传递,并且它不允许在存储过程中被重新赋值。如果存储过程的参数没有指定存参数传递类型,默认为IN

create or replace procedure proc1(

p_para1 varchar2,

p_para2 out varchar2,

p_para3 in out varchar2

)as

v_name varchar2(20);

begin

p_para1 :=‘aaa’;

p_para2 :=‘bbb’;

v_name := ‘素小暖’;

p_para3 := v_name;

dbms_output.put_line(‘p_para3:’||p_para3);

null;

end;

OUT 参数:作为输出参数,需要注意,当一个参数被指定为OUT类型时,就算在调用存储过程之前对该参数进行了赋值,在存储过程中该参数的值仍然是null.

INOUT 是真正的按引用传递参数。即可作为传入参数也可以作为传出参数。

对于IN参数,其宽度是由外部决定。

对于OUT 和IN OUT 参数,其宽度是由存储过程内部决定。

1.3 参数的默认值

存储过程的参数可以设置默认值

create or replace procedure procdefault(p1 varchar2,

p2 varchar2 default ‘mark’)

as

begin

dbms_output.put_line(p2);

end;

可以通过default 关键字为存储过程的参数指定默认值。在对存储过程调用时,就可以省略默认值。

需要注意的是:默认值仅仅支持IN传输类型的参数。OUT 和 IN OUT不能指定默认值

2. 存储过程内部块

2.1 内部块

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

Declare … begin … exception … end;

create or replace procedure innerBlock(p1 varchar2)

as

o1 varchar2(10) := ‘out1’;

begin

dbms_output.put_line(o1);

declare

inner1 varchar2(20);

begin

inner1 :=‘inner1’;

dbms_output.put_line(inner1);

declare

inner2 varchar2(20);

begin

inner2 := ‘inner2’;

dbms_output.put_line(inner2);

end;

exception

when others then

null;

end;

end;

需要注意变量的作用域。

3.存储过程的常用技巧

3.1 哪种集合?

我们在使用存储过程的时候经常需要处理记录集,也就是多条数据记录。分为单列多行和多列多行,这些类型都可以称为集合类型。我们在这里进行比较这些集合类型,以便于在编程时做出正确的选择。

索引表,也称为pl/sql表,不能存储于数据库中,元素的个数没有限制,下标可以为负值。

type t_table is table of varchar2(20) index by binary_integer;

v_student t_table;

varchar2(20)表示存放元素的数据类型,binary_integer表示元素下标的数据类型。

嵌套表,索引表没有 index by子句就是嵌套表,它可以存放于数据中,元素个数无限,下标从1开始,并且需要初始化

type t_nestTable is table of varchar2(20);

v_class t_nestTable ;

仅是这样声明是不能使用的,必须对嵌套表进行初始化,对嵌套表进行初始化可以使用它的构造函数

v_class :=t_nestTable(‘a’,‘b’,‘c’);

变长数组,变长数组与高级语言的数组类型非常相似,下标以1开始,元素个数有限。

type t_array is varray (20) of varchar2(20);

varray(20)就定义了变长数组的最大元素个数是20个

变长数组与嵌套表一样,也可以是数据表列的数据类型。

同时,变长数组的使用也需要事先初始化

由此可见,如果仅仅是在存储过程中当作集合变量使用,索引表是最好的选择。

3.2 选用何种游标?

显示游标分为:普通游标,参数化游标和游标变量三种。

下面以一个过程来进行说明

create or replace procedure proccursor(p varchar2)

as

v_rownum number(10) := 1;

cursor c_postype is select pos_type from pos_type_tbl where rownum =1;

cursor c_postype1 is select pos_type from pos_type_tbl where rownum = v_rownum;

cursor c_postype2(p_rownum number) is select pos_type from pos_type_tbl where rownum = p_rownum;

type t_postype is ref cursor ;

c_postype3 t_postype;

v_postype varchar2(20);

begin

open c_postype;

fetch c_postype into v_postype;

dbms_output.put_line(v_postype);

close c_postype;

open c_postype1;

fetch c_postype1 into v_postype;

dbms_output.put_line(v_postype);

close c_postype1;

open c_postype2(1);

fetch c_postype2 into v_postype;

dbms_output.put_line(v_postype);

close c_postype2;

open c_postype3 for select pos_type from pos_type_tbl where rownum =1;

fetch c_postype3 into v_postype;

dbms_output.put_line(v_postype);

close c_postype3;

end;

cursor c_postype is select pos_type from pos_type_tbl where rownum =1

这一句是定义了一个最普通的游标,把整个查询已经写死,调用时不可以作任何改变。

cursor c_postype1 is select pos_type from pos_type_tbl where rownum = v_rownum;

这一句并没有写死,查询参数由变量v_rownum来决定。需要注意的是v_rownum必须在这个游标定义之前声明。

cursor c_postype2(p_rownum number) is select pos_type from pos_type_tbl where rownum = p_rownum;

这一条语句与第二条作用相似,都是可以为游标实现动态的查询。但是它进一步的缩小了参数的作用域范围。但是可读性降低了不少。

type t_postype is ref cursor ;

c_postype3 t_postype;

先定义了一个引用游标类型,然后再声明了一个游标变量。

open c_postype3 for select pos_type from pos_type_tbl where rownum =1;

然后再用open for 来打开一个查询。需要注意的是它可以多次使用,用来打开不同的查询。

从动态性来说,游标变量是最好用的,但是阅读性也是最差的。

注意,游标的定义只能用使关键字IS,它与AS不通用。

3.3 游标循环最佳策略

我们在进行PL/SQL编程时,经常需要循环读取结果集的数据。进行逐行处理,这个过程就需要对游标进行循环。对游标进行循环的方法有多种,我们在此一一分析。

create or replace procedure proccycle(p varchar2)

as

cursor c_postype is select pos_type, description from pos_type_tbl where rownum < 6;

v_postype varchar2(20);

v_description varchar2(50);

begin

open c_postype;

if c_postype%found then

dbms_output.put_line(‘found true’);

elsif c_postype%found = false then

dbms_output.put_line(‘found false’);

else

dbms_output.put_line(‘found null’);

end if;

loop

fetch c_postype into v_postype,v_description ;

exit when c_postype%notfound;

dbms_output.put_line(‘postype:’||v_postype||‘,description:’||v_description);

end loop;

close c_postype;

dbms_output.put_line(‘—loop end—’);

open c_postype;

fetch c_postype into v_postype,v_description;

while c_postype%found loop

dbms_output.put_line(‘postype:’||v_postype||‘,description:’||v_description);

fetch c_postype into v_postype,v_description ;

end loop;

close c_postype;

dbms_output.put_line(‘—while end—’);

for v_pos in c_postype loop

v_postype := v_pos.pos_type;

v_description := v_pos.description;

dbms_output.put_line(‘postype:’||v_postype||‘,description:’||v_description);

end loop;

dbms_output.put_line(‘—for end—’);

end;

使用游标之前需要开打游标,open cursor,循环完后再关闭游标close cursor.

这是使用游标应该慎记于心的法则。

上面的过程演示了游标循环的三种方法。

在讨论循环方法之前,我们先看看%found和%notfound这些游标的属性。

open c_postype;

if c_postype%found then

dbms_output.put_line(‘found true’);

elsif c_postype%found = false then

dbms_output.put_line(‘found false’);

else

dbms_output.put_line(‘found null’);

end if;

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

第一种使用loop 循环

loop

fetch c_postype into v_postype,v_description ;

exit when c_postype%notfound;

……

end loop

这里需要注意,exit when语句一定要紧跟在fetch之后。必避免多余的数据处理。

处理逻辑需要跟在exit when之后。这一点需要多加小心。

循环结束后要记得关闭游标。

第二种使用while循环。

fetch c_postype into v_postype,v_description;

while c_postype%found loop

……

fetch c_postype into v_postype,v_description ;

end loop;

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

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

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

第三种 for循环

for v_pos in c_postype loop

v_postype := v_pos.pos_type;

v_description := v_pos.description;

end loop;

可见for循环是比较简单实用的方法。

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

其它,自动定义了一个记录类型及声明该类型的变量,并自动fetch数据到这个变量中。

我们需要注意v_pos 这个变量无需要在循环外进行声明,无需要为其指定数据类型。

它应该是一个记录类型,具体的结构是由游标决定的。

这个变量的作用域仅仅是在循环体内。

把v_pos看作一个记录变量就可以了,如果要获得某一个值就像调用记录一样就可以了。

如v_pos.pos_type

由此可见,for循环是用来循环游标的最好方法。高效,简洁,安全。

但遗憾的是,常常见到的却是第一种方法。所以从今之后得改变这个习惯了。

3.4 select into不可乎视的问题

我们知道在pl/sql中要想从数据表中向变量赋值,需要使用select into 子句。

但是它会带动来一些问题,如果查询没有记录时,会抛出no_data_found异常。

如果有多条记录时,会抛出too_many_rows异常。

这个是比较糟糕的。一旦抛出了异常,就会让过程中断。特别是no_data_found这种异常,没有严重到要让程序中断的地步,可以完全交给由程序进行处理。

create or replace procedure procexception(p varchar2)

as

v_postype varchar2(20);

begin

select pos_type into v_postype from pos_type_tbl where 1=0;

dbms_output.put_line(v_postype);

end;

执行这个过程

SQL> exec procexception(‘a’);

报错

ORA-01403: no data found

ORA-06512: at “LIFEMAN.PROCEXCEPTION”, line 6

ORA-06512: at line 1

处理这个有三个办法

1. 直接加上异常处理。

create or replace procedure procexception(p varchar2)

as

v_postype varchar2(20);

begin

select pos_type into v_postype from pos_type_tbl where 1=0;

dbms_output.put_line(v_postype);

exception

when no_data_found then

dbms_output.put_line(‘没找到数据’);

end;

这样做换汤不换药,程序仍然被中断。可能这样不是我们所想要的。

2. select into做为一个独立的块,在这个块中进行异常处理

create or replace procedure procexception(p varchar2)

as

v_postype varchar2(20);

begin

begin

select pos_type into v_postype from pos_type_tbl where 1=0;

dbms_output.put_line(v_postype);

exception

when no_data_found then

v_postype := ‘’;

end;

dbms_output.put_line(v_postype);

end;

这是一种比较好的处理方式了。不会因为这个异常而引起程序中断。

3.使用游标

create or replace procedure procexception(p varchar2)

as

v_postype varchar2(20);

cursor c_postype is select pos_type from pos_type_tbl where 1=0;

begin

open c_postype;

fetch c_postype into v_postype;

close c_postype;

dbms_output.put_line(v_postype);

end;

这样就完全的避免了no_data_found异常。完全交由程序员来进行控制了。

第二种情况是too_many_rows 异常的问题。

Too_many_rows 这个问题比起no_data_found要复杂一些。

给一个变量赋值时,但是查询结果有多个记录。

处理这种问题也有两种情况:

1. 多条数据是可以接受的,也就是说从结果集中随便取一个值就行。这种情况应该很极端了吧,如果出现这种情况,也说明了程序的严谨性存在问题。

2. 多条数据是不可以被接受的,在这种情况肯定是程序的逻辑出了问题,也说是说原来根本就不会想到它会产生多条记录。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!

我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:

Dubbo面试专题

JVM面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Java并发面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Kafka面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MongDB面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MyBatis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MySQL面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Netty面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

RabbitMQ面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Redis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Spring Cloud面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

SpringBoot面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

zookeeper面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

常见面试算法题汇总专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

计算机网络基础专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

设计模式专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南
-3rr8CW1Y-1712102605850)]

Java并发面试专题

[外链图片转存中…(img-GfU5NpC5-1712102605851)]

Kafka面试专题

[外链图片转存中…(img-INogQ1OH-1712102605851)]

MongDB面试专题

[外链图片转存中…(img-efRDbQq5-1712102605851)]

MyBatis面试专题

[外链图片转存中…(img-INgD86xr-1712102605852)]

MySQL面试专题

[外链图片转存中…(img-dTwuqx9F-1712102605852)]

Netty面试专题

[外链图片转存中…(img-V06meTxI-1712102605852)]

RabbitMQ面试专题

[外链图片转存中…(img-faHVqPT5-1712102605853)]

Redis面试专题

[外链图片转存中…(img-J1oWRIgt-1712102605853)]

Spring Cloud面试专题

[外链图片转存中…(img-hrYAPFZN-1712102605853)]

SpringBoot面试专题

[外链图片转存中…(img-Y8OG6nXF-1712102605854)]

zookeeper面试专题

[外链图片转存中…(img-eXgYwFXX-1712102605854)]

常见面试算法题汇总专题

[外链图片转存中…(img-j62bcaRR-1712102605854)]

计算机网络基础专题

[外链图片转存中…(img-3OcnuUPo-1712102605855)]

设计模式专题

[外链图片转存中…(img-PfRoJ7gi-1712102605855)]

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值