6.3 存储过程
    6.3.1 创建过程
    建立存储过程
    在 ORACLE SERVER上建立存储过程,可以被多个应用程序调用,可以向存储过程传递参数,也可以向存储过程传回参数.
    创建过程语法:

    1. CREATE [OR REPLACE] PROCEDURE procedure_name
    2. ([arg1 [ IN | OUT | IN OUT ]] type1 [DEFAULT value1],
    3. [arg2 [ IN | OUT | IN OUT ]] type2 [DEFAULT value1]],
    4. ......
    5. [argn [ IN | OUT | IN OUT ]] typen [DEFAULT valuen])
    6. [ AUTHID DEFINER | CURRENT_USER ]
    7. { IS | AS }
    8. --<声明部分>
    9. BEGIN
    10. --<执行部分>
    11. EXCEPTION
    12. -- <可选的异常错误处理程序>
    13. END procedure_name;

    相关参数说明参见函数的语法说明。

    --流水号过程
    create or replace procedure max_bh(sasettleid in number) as 
    v_old_num    NUMBER;--上一条记录中的编号数
      v_new_num    VARCHAR2(10);--新记录的编号数
      v_old_no     VARCHAR2(50);--原流水号
      v_maked_no   VARCHAR2(50);--新流水号
      v_date_no    VARCHAR2(20);--当前日期
      v_sql        VARCHAR2(4000);
      v_number_col VARCHAR2(20);--记录最大编号字段
      v_table_name VARCHAR2(20);--记录最大编号的表
    
    begin 
    v_number_col:='nzdbh';
    v_table_name:='zddjbh';
    
    v_sql:='select max(nzdbh) from' || v_table_name;
    execute imeediate v_sql into v_old_no;
    
    v_sql:='select substr(to_char(sysdate,''YYYYMMDD''),1,8) from dual';
    execute immediate v_sql into v_date_no;
    
    v_old_num:=to_number(substr(v_date_no,9,4));
    v_new_num:=to_char(v_old_num+1);
    
    while(length(v_new_num)<4) loop
    v_new_num:='0'||v_new_num;
    end loop;
    
    if v_old_no is null or substr(v_old_no,1,8)<>v_date_no
    then v_maked_no:=v_date_no||'0001';
    else v_maked_no:=v_date_no||v_new_num;
    end if;
    
    insert into ZDDJBH (NZDBH,sasettleid) values (v_maked_no,V_SASETTLEID);
    
    end;
    

    6.3.2 调用存储过程
    存储过程建立完成后,只要通过授权,用户就可以在SQLPLUS 、ORACLE开发工具或第三方开发工具中来调用运行。对于参数的传递也有三种:按位置传递、按名称传递和组合传递,传递方法与函数的一样。ORACLE 使用EXECUTE 语句来实现对存储过程的调用:
    EXEC[UTE] procedure_name( parameter1, parameter2…);
    例10:
    EXECUTE logexecution;
    例12.计算指定部门的工资总和,并统计其中的职工数量。

     CREATE OR REPLACE PROCEDURE proc_demo (dept_no NUMBER DEFAULT 10,sal_sum OUT NUMBER,emp_count OUT NUMBER)
     IS
     BEGIN
     SELECT SUM(salary), COUNT(*) INTO sal_sum, emp_count
     FROM employees WHERE department_id = dept_no;
     EXCEPTION
     WHEN NO_DATA_FOUND THEN
           DBMS_OUTPUT.PUT_LINE('温馨提示:你需要的数据不存在!');
     WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
     END proc_demo;
      DECLARE
     V_num NUMBER;
     V_sum NUMBER(8, 2);
     BEGIN
       Proc_demo(30, v_sum, v_num);
     DBMS_OUTPUT.PUT_LINE('温馨提示:30号部门工资总和:'||v_sum||',人数:'||v_num);
       Proc_demo(sal_sum => v_sum, emp_count => v_num);
     DBMS_OUTPUT.PUT_LINE('温馨提示:10号部门工资总和:'||v_sum||',人数:'||v_num);
     END;
    
    在PL/SQL 程序中还可以在块内建立本地函数和过程,这些函数和过程不存储在数据库中,但可以在创建它们的PL/SQL 程序中被重复调用。本地函数和过程在PL/SQL 块的声明部分定义,它们的语法格式与存储函数和过程相同,但不能使用CREATE OR REPLACE 关键字。<br />    ORACLE8i 可以支持事务处理中的事务处理的概念.这种子事务处理可以完成它自己的工作,独立于父事务处理进行提交或者回滚.通过使用这种方法,开发者就能够这样的过程,无论父事务处理是提交还是回滚,它都可以成功执行.<br />6.3.7 过程与函数的比较<br />使用过程与函数具有如下优点:<br />1、共同使用的代码可以只需要被编写和测试一次,而被需要该代码的任何应用程序(如:.NET、C++、JAVA、VB程序,也可以是DLL库)调用。<br />2、这种集中编写、集中维护更新、大家共享(或重用)的方法,简化了应用程序的开发和维护,提高了效率与性能。<br />3、这种模块化的方法,使得可以将一个复杂的问题、大的程序逐步简化成几个简单的、小的程序部分,进行分别编写、调试。因此使程序的结构清晰、简单,也容易实现。<br />4、可以在各个开发者之间提供处理数据、控制流程、提示信息等方面的一致性。<br />5、节省内存空间。它们以一种压缩的形式被存储在外存中,当被调用时才被放入内存进行处理。并且,如果多个用户要执行相同的过程或函数时,就只需要在内存中加载一个该过程或函数。<br />6、提高数据的安全性与完整性。通过把一些对数据的操作放到过程或函数中,就可以通过是否授予用户有执行该过程或的权限,来限制某些用户对数据进行这些操作。<br />过程与函数的相同功能有:<br />1、 都使用IN模式的参数传入数据、OUT模式的参数返回数据。<br />2、 输入参数都可以接受默认值,都可以传值或传引导。<br />3、 调用时的实际参数都可以使用位置表示法、名称表示法或组合方法。<br />4、 都有声明部分、执行部分和异常处理部分。<br />5、 其管理过程都有创建、编译、授权、删除、显示依赖关系等。<br />使用过程与函数的原则:<br />1、如果需要返回多个值和不返回值,就使用过程;如果只需要返回一个值,就使用函数。<br />2、过程一般用于执行一个指定的动作,函数一般用于计算和返回一个值。<br />3、可以SQL语句内部(如表达式)调用函数来完成复杂的计算问题,但不能调用过程。所以这是函数的特色。<br />注:Oracle 的存储过程里没有declare的语法,触发器和plsql块才是declare,如果要定义变量,后面直接跟is的。