第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. 存储过程和语句块有什么区别?

你可能感兴趣的:(第10章 存储过程)