ORACLE之存储过程和函数

存储过程

定义

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。

语法
create or replace procedure
  <过程名>[参数名 参数模式(in/out/int out) 数据类型:=value]
 begin
   PL/SQL语句;
 end;
参数模式
  • In 参数

输入参数,调用时存储过程待接收的参数
可以是常数,数据量,初始化变量或表达式

创建带in参数存储过程

create or replace procedure
  pro_InsertClassInfo(strClassID varchar2,strClassName Varchar2)
is
begin
  insert into classinfo(classid,classname)
  values(strClassID,strClassName);
end;

调用存储过程

exec pro_insertclassinfo('201611520','计算机科学与技术');

![pictwo.png](https://upload-images.jianshu.io/upload_images/8176895-f4610efad5c30a8d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

示列

创建存储过程,若记录存在则更新,不存在则添加记录

create or replace procedure
  pro_merageclassinfo(strid varchar2,strname varchar2)
is
  recount int;
begin
  select count(*) into recount from classinfo where classid=strid;
  if recount>0 then
    update classinfo set classname=strname where classid=strid;
  else
    insert into classinfo(classid,classname) values (strid,strname);
  end if;
end;



exec pro_merageclassinfo('201611520','大数据与智能工程');
// classid已存在执行更新操作
exec pro_merageclassinfo('201811520','区块链技术');
//新纪录执行插入操作
  • Out 参数

输出参数,存储过程运行后的结果赋值给输出参数,显示到屏幕
参数只能是变量,不能是常数或表达式

create or replace procedure
  pro_getavgscore(strno varchar2,avgscore out number)
is
begin
  select avg(studscore) into avgscore from studscoreinfo
  where studno=strno;
end;

调用存储过程

declare
  avgscore number;
begin
  pro_getavgscore('20010704035',avgscore);
  dbms_output.put_line(avgscore);
end;

<meta charset="utf-8">

picone.png
  • In Out 参数

输入和输出,接受值并返回已更新的值
参数只能是变量,不能是常数或表达式

创建存储过程

create or replace procedure 
  Pro_getstudscore(strno varchar2,avgscore in out number)
is
begin
  dbms_output.put_line(avgscore+5);
  select avg(studscore) into avgscore 
  from studscoreinfo
  where studno=strno;
end;

调用存储过程

declare
  avgscore number;
begin
  Pro_getstudscore('20010505001',avgscore);
  dbms_output.put_line(avgscore);
end;

函数

语法
create or replace function
  <函数名>[参数1,参数2...参数n]
return 返回值的数类型 
is
begin
  PL/SQL语句;
end;

参数说明
(变量名1 数据类型1:=value1,变量名2 数据类型2:=value2)

函数实例

学生成绩统分函数,规则:多选或错选或不选给0分,少选给选对的分

create or replace function 
  getitemscore(Stand_ans varchar ,custor_ans varchar2)//参数是数据表中的标准答案和学生的答案
return int  //函数的返回值是int类型
is
  Lencustor int:=length(custor_ans);//获取学生答案的长度
begin
    if Lencustor>length(Stand_ans) or Custor_ans is null then
      return 0;//多选或没选返回0分
    end if;
    for i in 1..Lencustor
    loop
      if instr(Stand_ans,substr(custor_ans,i,1)) = 0 then
        return 0;//如果学生答案中有记录没在标准答案中,即有错选答案
      end if;
    end loop;
    return Lencustor; //没有错选,给选对的分,分数就是答案的长度
end;

测试这个统分函数

select getitemscore('ABC','AC') from dual;
//少选的情况
select getitemscore('AC','ABC') from dual;
//多选的情况
select getitemscore('ABC','ACD') from dual;
//错选的情况
picthree.png

统计600个学生共60000条记录的分数

select studno,
sum(getitemscore(stand_anx,custor_anx))*100/
sum(Length(stand_anx)) as studscore
from answer
group by studno
picfour.png

ps:六万条数据统分,set timing on,所花时间是1.46s,oracle是真的牛逼

练习

  1. 编写一个函数,实现求N!(即N 的阶乘),测试5!(即5 的阶乘)。

A.创建函数

create or replace function getjc(n int)
  return number 
 is
  k number:=1;
begin
  for i in 1..n
  loop
    k:=k*i;
  end loop;
  return k;
end;

B.调用函数

select getjc(5) from dual;
  1. 创建一个简单的存储过程,求S=1!+2!+3!+4!+…+N!,直到S 大于10000 时N 的值和S的值。(注:阶乘可以写一个函数完成)

A.创建存储过程

create or replace procedure
  proce_getsumjc(k out number,s out number)
is
  i number:=1;
begin
  s:=0;
  k:=1;
loop
  k:=K*i;
  i:=i+1;
  s:=s+k;
  if s > 10000 then
    exit;
  end if;
end loop;
  dbms_output.put_line('s='||s);
  dbms_output.put_line('n='||k);
end;

B.调用存储过程

declare
  K number;
  s number;
begin
  proce_getsumjc(k,s);
end;
  1. 创建一个带输入参数的存储过程,输入分数参数,执行存储过程得到平均分大于该分数的学生统计成绩信息(包括学号,姓名,平均分,课程门数字段)。

A.创建存储过程

create or replace procedure procedure_avg(inputscore number) 
is
  sstudno studinfo.studno%Type;
  sstudname studinfo.studname%Type;
  savgscore studscoreinfo.studscore%Type;
  coursecount number;
cursor mycur is 
  select s.studno,studname,avg(studscore),count(*) count
  from studinfo s,studscoreinfo ss
  where s.studno=ss.studno
  group by s.studno,studname
  having avg(studscore)> inputscore;
begin
  open mycur;
  fetch mycur into sstudno,sstudname,savgscore,coursecount;
  while mycur%found
  loop
    dbms_output.put_line(sstudno||sstudname||savgscore||coursecount);
    fetch mycur into sstudno,sstudname,savgscore,coursecount;
  end loop;
close mycur;
end;
//这里会查询出多条记录,oracle并不能操作一个结果集,只能通过游标取出每条记录,我将下一篇博客学习游标

B.调用存储过程

exec procedure_avg(80); 
  1. 创建带两个输入参数和一个输出参数的存储过程,执行存储过程时,输入参数为分数段,输出参数为得到该分数段的人数。

A.创建存储过程

create or replace procedure 
  procedure_count(minscore in number,maxscore in number,countp out number) 
is
begin
  select count(*) into countp
  from
  (
  select studno
  from studscoreinfo
  group by studno
  having avg(studscore) between minscore and maxscore
 );
  dbms_output.put_line(countp);
end;

B.调用存储过程

declare
  countp number;
begin
  procedure_count(60,70,countp); 
end;
  1. 创建一个学生成绩统计函数(GetEveryItemScore),多选记 0 分,少选记选对分。

A.创建函数

Create Or Replace Function GetItemScore(Stand_Ans
varchar2,Custor_Ans varchar2)
return int is
LenCustor int:=length(Custor_Ans);
begin
  if LenCustor>length(stand_ans) or Custor_Ans IS NULL then
  return 0;//多选或没选返回0分
end if;
for i in 1..LenCustor
loop
  if instr(stand_ans,substr(custor_ans,i,1))=0 then
  return 0;
end if;//如果学生答案中有记录没在标准答案中,即有错选答案
end loop;
  return LenCustor;//返回答案的长度即得分
end;

B.调用函数

select getitemscore('ABC','BC') from dual;
  1. 将当前文件夹下电子表格(StudScore.xls)所有数据导入到自己的数据库中,利用题目 5 中创建的函数统计各学生成绩。

A.创建表

答案表

create table Answer
(
stand_anx varchar2(15),
custor_anx varchar2(15),
studno varchar2(20)
)

成绩表

create table studscore
(
studno varchar2(15) primary key,
studname varchar2(15),
studscore number(4,1)
)

B.导入数据

load data infile 'c:\csv'
append into table answer
fields terminated by ','
(stand_anx,custor_anx,studno)


load data infile 'c:\StudScore.csv'
append into table studscore
fields termiated by ','
(studno,studname,studscore)

C.计算得分

select studno,
sum(getitemscore(stand_anx,custor_anx))*100/
sum(Length(stand_anx)) as studscore
from answer
group by studno
  1. 利 用 6 题 查 询 结 果 , 创 建 一 个 学 生 成 绩 统 计 视 图 ( ViewGetStudScore ), 包 括StudNo,StudScore 字段。并写出将视图中的成绩更新到表 StudScore 中的 SQL 语句。
merge into studscore
using v_getstudcore
on(v_getstudcore.studno=studscore.studno)
when matched then
update set studscore.studscore=v_getstudcore.studscore
  1. 利用 7题的结果,将表StudScore中的前20名(以分数高低排)导入新表(Top20StudScore),包括学号、姓名、成绩字段。
create table top20studscore
as
select * from 
(
select * from studscore
order by score desc
)A
where rownum<=20
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容