一:编写

定义:

CREATE [OR REPLACE]PROCEDURE procedure_name
    [(argument_name [IN | OUT | IN OUT] argument_type)]
    AS | IS
    BEGIN
        procedure_body;
    END [procedure_name];


--小事例

--例:定义一个过程,以JOB为参数,查询该JOB的最高工资、最低工资、平均工资。
    CREATE OR REPLACE PROCEDURE display_sal(v_job emp.job%TYPE)   --该形参缺省为in类型,数据类型为emp.job%TYPE
    AS
         v_avg_sal emp.sal%TYPE;
         v_max_sal emp.sal%TYPE;
         v_min_sal emp.sal%TYPE;
    BEGIN
         SELECT avg(sal) INTO v_avg_sal FROM emp WHERE job=v_job;
         SELECT max(sal) INTO v_max_sal FROM emp WHERE Job=v_job;
         SELECT min(sal) INTO v_min_sal FROM emp WHERE job=v_job;
         DBMS_OUTPUT.PUT_LINE('DEPT '||v_job||' avg sal:'||v_avg_sal);
         DBMS_OUTPUT.PUT_LINE('DEPT '||v_job||' max sal:'||v_max_sal);
         DBMS_OUTPUT.PUT_LINE('DEPT '||v_job||' min sal:'||v_min_sal);
                                                                                                                                               
    EXCEPTION
         WHEN NO_DATA_FOUND THEN
              DBMS_OUTPUT.PUT_LINE('NOT FOUND RECORD!');
    END display_sal;
    /
    scott@ORCL> set serveroutput on;
    scott@ORCL> exec display_sal('SALESMAN');
    DEPT SALESMAN avg sal:1400
    DEPT SALESMAN max sal:1600
    DEPT SALESMAN min sal:1250
    PL/SQL procedure successfully completed.

--无参数

CREATE OR REPLACE PROCEDURE display_systime
         AS
         BEGIN
              DBMS_OUTPUT.PUT_LINE('CURRENT TIME IS '||sysdate);
         END display_systime;
         /
                                                                                                                                    
         execute display_systime;     --调用

--in参数

--例:定义一个添加记录的过程(全部为输入参数)
             CREATE OR REPLACE PROCEDURE add_emp
             (
             v_no IN emp.empno%TYPE,
             v_name IN emp.ename%TYPE,
             v_dept IN emp.deptno%TYPE default 20   --此过程中指定了缺省的输入值,即部门号为
             )
             AS
             BEGIN
                  INSERT INTO emp (empno,ename,deptno) VALUES (v_no,v_name,v_dept);
             EXCEPTION
                  WHEN DUP_VAL_ON_INDEX THEN
                      DBMS_OUTPUT.PUT_LINE('Record Is Exist!');
             END add_emp;
             /
             execute add_emp(8000,'TEST2',20);   --调用

--out参数

--例:定义一个输入员工编号,修改记录,再返回修改后的结果(姓名和工资)。
             CREATE OR REPLACE PROCEDURE ed_emp
             (
             v_no IN emp.empno%TYPE,      --定义了一个in类型,二个out类型的参数
             v_name OUT emp.ename%TYPE,
             v_sal OUT emp.sal%TYPE
             )
             AS
             BEGIN
                  UPDATE emp SET sal=sal+100 WHERE empno=v_no;
                  SELECT ename,sal INTO v_name,v_sal FROM emp WHERE empno=v_no;
             EXCEPTION
                  WHEN NO_DATA_FOUND THEN
                      DBMS_OUTPUT.PUT_LINE('NOT FOUND RECORD!');
             END ed_emp;
             /
             scott@ORCL> VARIABLE t_name varchar2(20);
             scott@ORCL> VARIABLE t_sal number;
             scott@ORCL> call ed_emp(7788,:t_name,:t_sal);
             Call completed.
             scott@ORCL> print t_name t_sal;
             T_NAME
             --------------------------------
             SCOTT
                   T_SAL
             ----------
                    3100

--in out参数

--例:IN OUT类型参数的使用
              CREATE OR REPLACE PROCEDURE comp
              (num1 IN OUT NUMBER,num2 IN OUT NUMBER)
              AS
                   v1 NUMBER;
                   v2 NUMBER;
              BEGIN
                   v1:=num1+num2;
                   v2:=num1*num2;
                   num1:=v1;
                   num2:=v2;
              END;
              /
                                                                                                                      
              scott@ORCL> var n1 number;
              scott@ORCL> var n2 number;
              scott@ORCL> exec :n1:=5;
              scott@ORCL> exec :n2:=3;
              scott@ORCL> exec comp(:n1,:n2); 
              scott@ORCL> print n1 n2;
                                                                                                          
                       N1
              ----------
                        8
                                                                                                          
                                                                                                          
                       N2
              ----------
                       15

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

按位置传递:

实参按顺序将值传给形参

EXECUTE ED_EMP(7900,:t_name,:t_sal);

EXECUTE ED_EMP(8000,'TEST2',20);


按名字传递

EXECUTE ED_EMP(v_name=>'ABCDE',v_dept=>10,v_no=>8003);


混合传递

EXECUTE ED_EMP(8005,v_dept=>20,v_name=>'TEST5');




二:创建方式

同函数的创建方式,将http://fuwenchao.blog.51cto.com/6008712/1363860


三:调用

1:EXECUTECALL procedure_name [(argument_list)]



四:查看

查看系统过程信息

    DBA_OBJECTS

    DBA_PROCEDURES

    DBA_SOURCE

USER_SOURCE, ALL_SOURCE, DBA_SOURCE, USER_ERRORS,

ALL_PROCEDURES,USER_OBJECTS,ALL_OBJECTS,DBA_OBJECTS

--使用desc procedure_name 查看存储过程的参数信息

         scott@ORCL>desc ed_emp;
PROCEDURE ed_emp
          Argument NameTypeIn/Out Default?
------------------------------ ----------------------- ------ --------
          V_NO                           NUMBER(4)IN
          V_NAME                         VARCHAR2(10)            OUT
          V_SAL                          NUMBER(7,2)             OUT

--从dba_objects获得存储过程的信息

      idle>select owner,object_name,object_type,status from dba_objects whereobject_name='ED_EMP';
         OWNER                          OBJECT_NAME          OBJECT_TYPE     STATUS
------------------------------ -------------------- --------------- -------
         SCOTT                          ED_EMP               PROCEDURE       VALID
         scott@ORCL>selectobject_name,procedure_name,interface,authid from user_procedures;
OBJECT_NAME          PROCEDURE_NAME                 INT AUTHID
-------------------- ------------------------------ --- ------------
         DISPLAY_SAL                                         NO  DEFINER
         ED_EMP                                              NO  DEFINER



--查看存储过程的源代码

scott@ORCL>select line,textfrom user_source wherename='ED_EMP';
                LINE TEXT
---------- --------------------------------------------------------------------------------
                    1 PROCEDURE ed_emp
                    2       (
                    3       v_no IN emp.empno%TYPE,
                    4       v_name OUT emp.ename%TYPE,
                    5       v_sal OUT emp.sal%TYPE
                    6       )
                    7       AS
                    8       BEGIN
                    9         UPDATE emp SET sal=sal+100 WHERE empno=v_no;
                   10         SELECT ename,sal INTO v_name,v_sal FROM emp WHERE empno=v_no;
                   11       EXCEPTION
                  12         WHEN NO_DATA_FOUND THEN
                   13           DBMS_OUTPUT.PUT_LINE('NOT FOUND RECORD!');
                   14       END ed_emp;


--查看错误信息

        SHOW ERRORS


scott@ORCL>CREATEORREPLACEPROCEDURE comp
           2  (num1 IN OUT NUMBER,num2 IN OUT NUMBER)
           3  AS
           4  v1 NUMBER;
           5  v2 NUMMBER;
           6  BEGIN
           7    v1:=num1+num2;
           8    v2:=num1*num2;
           9    num1:=v1;
          10    num2:=v2;
          11  END;
          12  /
         Warning:Procedure created with compilation errors.
         scott@ORCL> show errors;
         Errors forPROCEDURE COMP:
         LINE/COL ERROR
-------- -----------------------------------------------------------------
         5/4      PL/SQL: Item ignored
         5/4      PLS-00201: identifier 'NUMMBER' must be declared
         8/3      PL/SQL: Statement ignored
         8/3      PLS-00320: the declaration of the typeof this expression is
                    incomplete or malformed
         10/3     PL/SQL: Statement ignored
         10/9     PLS-00320: the declaration of the typeof this expression is
                    incomplete or malformed




五:授权

CREATE ANY PROCEDURE

DROP ANY PROCEDURE

GRANT system_privilege | role
TO user | role | PUBLIC [WITH ADMIN OPTION]
-
GRANT object_privilege | ALL ON schema.object
TO user | role | PUBLIC [WITH GRANT OPTION]
--例子:
CREATE OR REPLACE PUBLIC SYNONYM dbms_job FOR dbms_job
-
GRANT EXECUTE ON dbms_job TO PUBLIC WITH GRANT OPTION

六:删除

删除过程;DROPPROCEDURE procedure_name

         scott@ORCL>dropprocedure comp;
Procedure dropped.

七:开发过程

开发存储过程、函数、包及触发器的步骤如下:


1 使用文字编辑处理软件编辑存储过程源码

使用文字编辑处理软件编辑存储过程源码,要用类似WORD 文字处理软件进行编辑时,要将源码存为文本格式。


2 SQLPLUS或用调试工具将存储过程程序进行解释

SQLPLUS或用调试工具将存储过程程序进行解释;

SQL>下调试,可用START GET ORACLE命令来启动解释。如:

SQL>START c:\stat1.sql

如果使用调式工具,可直接编辑和点击相应的按钮即可生成存储过程。


3 调试源码直到正确

我们不能保证所写的存储过程达到一次就正确。所以这里的调式是每个程序员必须进行的工作之一。在SQLPLUS下来调式主要用的方法是:

l使用 SHOW ERROR命令来提示源码的错误位置;

l使用 user_errors 数据字典来查看各存储过程的错误位置。

--

如果使用PL/SQL Developer 或者TOAD 工具的话,调试还是很方便的。 如果是在Sqlplus里,我们可以使用:

           SQL>show errors

来查看错误。不过在开发中估计也很少有人直接使用sqlplus来写存储过程。 效率低,调试又麻烦。 还是使用工具方便点。我一直使用的是Toad的。

如果想在某处退出存储过程,直接使用Return;就可以了。 与存储过程编写相关的数组和游标, 这两块说起来还是有很多东西。 在上面的示例中,也简单的举了几个有关游标与存储过程编写的例子。

总之,写代码都是都是费脑子的事,相比之下还是做管理DBA舒服点,虽然压力大很多,至少不用这么费心思去整理业务逻辑。

4 授权执行权给相关的用户或角色

如果调式正确的存储过程没有进行授权,那就只有建立者本人才可以运行。所以作为应用系统的一部分的存储过程也必须进行授权才能达到要求。在SQL*PLUS下可以用GRANT命令来进行存储过程的运行授权。



八:过程和函数比较

Oracle 存储过程定义优点函数区别

http://blog.csdn.net/tianlesoftware/archive/2010/01/27/5261364.aspx

Oracle 查看存储过程触发器函数等对象定义语句的方法

http://blog.csdn.net/tianlesoftware/archive/2010/06/19/5679293.aspx



使用过程与函数具有如下优点:


1、共同使用的代码可以只需要被编写和测试一次,而被需要该代码的任何应用程序(如:.NETC++JAVAVB程序,也可以是DLL库)调用。

2、这种集中编写、集中维护更新、大家共享(或重用)的方法,简化了应用程序的开发和维护,提高了效率与性能。

3、这种模块化的方法,使得可以将一个复杂的问题、大的程序逐步简化成几个简单的、小的程序部分,进行分别编写、调试。因此使程序的结构清晰、简单,也容易实现。

4、可以在各个开发者之间提供处理数据、控制流程、提示信息等方面的一致性。

5、节省内存空间。它们以一种压缩的形式被存储在外存中,当被调用时才被放入内存进行处理。并且,如果多个用户要执行相同的过程或函数时,就只需要在内存中加载一个该过程或函数。

6、提高数据的安全性与完整性。通过把一些对数据的操作放到过程或函数中,就可以通过是否授予用户有执行该过程或的权限,来限制某些用户对数据进行这些操作。


过程与函数的相同功能有:

1、 都使用IN模式的参数传入数据、OUT模式的参数返回数据。

2、 输入参数都可以接受默认值,都可以传值或传引导。

3、 调用时的实际参数都可以使用位置表示法、名称表示法或组合方法。

4、 都有声明部分、执行部分和异常处理部分。

5、 其管理过程都有创建、编译、授权、删除、显示依赖关系等。


使用过程与函数的原则:

1、如果需要返回多个值和不返回值,就使用过程;如果只需要返回一个值,就使用函数。

2、过程一般用于执行一个指定的动作,函数一般用于计算和返回一个值。

3、可以SQL语句内部(如表达式)调用函数来完成复杂的计算问题,但不能调用过程。所以这是函数的特色。



参考:

http://blog.csdn.net/tianlesoftware/article/details/6147230