第10章 存储过程

target

掌握什么是存储过程
掌握存储过程的作用
掌握存储过程的创建
掌握存储过程的修改与删除

1. 什么是存储过程

存储过程在数据库开发中使用比较频繁,它有着普通SQL语句不可替代的作用。

1.1 认识存储过程

存储过程可以通俗地理解为是存储在数据库服务器中的封装了一段或多段SQL语句的PL/SQL代码块。在数据库中有一些是系统默认的存储过程,那么可以直接通过存储过程的名称进行调用。另外,存储过程还可以在编程语言中调用,如Java、C#等编程语言。

1.2 存储过程的作用

  • 简化复杂的操作。

    存储过程可以把需要执行的多条SQL语句封装到一个独立单元中,用户只需调用这个单元就能达到目的。这样就实现了一人编写多人调用,同时缩短了平均开发周期,为公司节省了成本。

  • 增加数据独立性。

    与视图的效果类似,利用存储过程可以把数据库基础数据和程序 (或用户)隔离开来,当基础数据的结构发生变化时,可以修改存储过程,这样对程序来说基础数据的变化是不可见的,也就不需要修改程序代码了。

  • 提高安全性

    使用存储过程有效地降低了错误出现的几率。如果不使用存储过程要想实现某项操作可能需要执行多条单独的SQL语句,而过多的执行步骤很可能造成更高的出错几率。不仅如此,实际工作中开发人员的水平参差不齐,由高水平的人编写存储过程,水平较低的人员直接调用,这样就能避免很多不必要的错误发生。此外,存储
    过程也可以进行权限设置。

  • 提高性能。完成一项复杂的功能可能需要多条SQL语句,同时SQL每次执行都需要编译, 而存储过程可以包含多条SQL语句,而且创建完成后只需要编译一次,以后就可以直接调用,从这方面来看存储过程可以提高性能。如果程序语言要实现某项比较复杂的功能, 它会多次连接数据库,在使用存储过程的情况下,程序只需连接一次就能达到目的。

1.3 存储过程的语法

CREATE ( OR REPLACE ] PROCEDURE [ schema. ] procedure_name
[parameter_name [ [ IN ] datatype [ { := | DEFAULT } expression ] 
    | { OUT | IN OUT } ( NOCOPY ] datatype
  ] [,...]
    { is | as}
  body;

其中各项参数介绍如下:

  • OR REPLACE:表示如果指定的过程已经存在,则覆盖同名的存储过程。

  • schema:表示该存储过程的所属机构。

  • procedure_name:创建存储过程的名称。

  • parameter_name:表示存储过程中的参数名称。

  • [IN] datatype [ { := I DEFAULT } expression ]:整个这段语法表示传入参数的数据类型以及默认值。其中,datatype项表示参数的数据类型,[{ := I DEFAULT } expression ] 项表示参数的默认值的写法。

  • { OUT | IN OUT } [ NOCOPY ] datatype:表示存储过程的参数类型,不过和上面介绍 的IN有所区别。其中,OUT表示输出参数,IN OUT表示既可输入也可输出的参数, datatype依旧表示参数类型。

  • { IS | AS }:连接词。

  • BODY:表示函数体,是存储过程的具体操作部分,通常在begin...end中。

注意:

存储过程的参数默认类型是IN型的,也就是说是传入型的。

创建存储过程需要有CREATE PROCEDURE权限。

2. 在SQL *Plus中创建存储过程

2.1 hello world存储过程

create procedure helloworld as
begin
    dbms_output.put_line('Hello Wolrd');
end;
/

执行效果:

① serveroutput设置

要想让dbms_output.put_line成功输出,需要把serveroutput选项设置为ON状态。默认情况是OFF状态的。可以执行如下语句查看:

show serveroutput

打开输出设置:

set serveroutput on

② 执行存储过程

begin
    helloworld;
end;
/

输出:

Hello Wolrd

PL/SQL 过程已成功完成。

还可以通过关键词exec执行存储过程:

exec helloworld;

2.2 查看存储过程

存储过程一旦被创建就会存储到数据库服务器上,Oracle允许开发人员查看已经存在的存储过程脚本,这可以到视图USER_SOURCE里査看。

🌰:査看存储过程helloworld的脚本

SELECT * FROM USER_SOURCE WHERE NAME = 'HELLOWORLD' ORDER BY LINE;

注意:过程名需要全部大写。

2.3 显示存储过程的错误

语法:

show errors procedure produce_name;

🌰:故意写错一个存储过程,然后查看错误

① 创建存储过程:

create procedure test_err as
begin   
  dbms_output.put_lin('Hello Wolrd');
end;
/

输出:

警告: 创建的过程带有编译错误。

② 查看存储过程的错误细节:

show errors procedure test_err;

输出:

PROCEDURE TEST_ERR 出现错误:

LINE/COL ERROR
-------- -----------------------------------------------------------------
3/1      PL/SQL: Statement ignored
3/13     PLS-00302: 必须声明 'PUT_LIN' 组件

2.4 无参存储过程

无参存储过程就是创建的存储过程不带任何参数,通常这种存储过程用做数据转换的几率 比较大。

🌰:把表PRODUCTINFO中价格最低的3件产品的description字段设置成“促销商品”,实现步骤如下:

(1) 将PRODUCTINFO中产品价格最低的3件产品査询出来。

(2) 把价格最低的3件产品description字段加上"促销商品”字样。

首先为PRODUCTINFO表添加一列description:

alter table productinfo add description varchar2(100);

创建存储过程的脚本如下:

create procedure product_update_prc as
begin
    update productinfo set description = '促销商品'
    where productid in
    (
    select productid from (select * from productinfo order by productprice) 
    where rownum < 4
  );
  commit;
end;
/

此时的过程还没有执行,只是编译通过了,执行后数据才会修改:

exec product_update_prc;

2.5 有参存储过程

存储过程允许带有参数,参数的使用将增加存储过程的灵活性,给数据库编程带来极大的方便。

存储过程中如果使用了参数,在执行存储过程时必须为其指定参数。参数可以是常量、变量、表达式等。

过程有输入、输出、输入输出三种参数。其中,输入参数 是默认的参数,也叫IN类型的参数。

🌰:根据输入的部门名称,从表emp中搜索出该部门员工的信息,并将其打印到屏幕

create procedure emp_intype_prc(parm_deptname in varchar2) as
    cur_deptno emp.deptno%type;                                     --存放部门名称
    cur_emp emp%rowtype;                                            --存放emp表中的行记录

begin
    --根据部门名字查出部门编号
    select deptno into cur_deptno
    from dept where dname=parm_deptname;
    
    if sql%found then
        dbms_output.put_line(parm_deptname || ':');
    end if;
    
    --从游标里面取值
    for my_emp_rec in 
  (
    select * from emp where deptno = cur_deptno
  )
        loop
            dbms_output.put_line('姓名:' || my_emp_rec.ename || ' 工作:' || my_emp_rec.job || ' 薪资:' || my_emp_rec.sal);
        end loop;
        
exception
    when no_data_found then
        dbms_output.put_line('没有数据');
    when too_many_rows then
        dbms_output.put_line('数据过多');
end;
/

执行:

SQL> exec emp_intype_prc('ACCOUNTING');
ACCOUNTING:
姓名:CLARK 工作:MANAGER 薪资:2450
姓名:KING 工作:PRESIDENT 薪资:5000
姓名:MILLER 工作:CLERK 薪资:1300

PL/SQL 过程已成功完成。

🌰:输出emp表的记录数

CREATE or replace PROCEDURE prc_empcount (empcount out number) as
BEGIN
    Select count(*) into empcount From emp;
END;
/

执行:

SQL> variable count number;
SQL> exec prc_empcount(:count);
SQL> print count;

     COUNT
----------
        14

3. 修改存储过程

修改存储过程内容要利用replace关键词。

在创建过程中需要开发人员自行带上or replace关键词,从而完成过程的修改,也就是覆盖。

4. 删除存储过程

语法:

drop procedure procedure_name;

🌰:删除 prc_empcount

drop procedure prc_empcount;

习题

一、填空题

  1. 存储过程参数分为( )、( )和( )3种类型。
  2. SQL *Plus使用( )命令来执行存储过程。
  3. SQL*Plus使用( )命令来显示错误信息。

二、选择題

  1. OUT类型的参数以使用下哪项填充?( )
    A. 常量 B. 变量
    C. 初始化后的变最 D. 函数

  2. 有输入参数的存储过程调用时能否不带参数?( )
    A.不能 B,能

三、简答题

  1. 为什么使用存储过程?

  2. 存储过程和语句块有什么区别?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容