PL/SQL --> 函数

系统 1668 0

--==================

-- PL/SQL --> 函数

--==================

 

    函数通常用于返回特定的数据。其实质是一个有名字的 PL / SQL 块,作为一个 schema 对象存储于数据库,可以被反复执行。函数通常被作为

一个表达式来调用或存储过程的一个参数,具有返回值。

 

一、建立函数的语法

    CREATE [ OR REPLACE ] FUNCTION function_name

        ( argument1 [mode1] datatype1 ,

          argument2 [mode2] datetype2 ,

          ...)

    RETURN datatype

    IS | AS

        [local_variable_declarations;...]

    BEGIN

        --actions;

        RETURN expression ;

    END [function_name] ;

   

    建立函数的几点注意事项

        1. 指定参数数据类型时 (argument) ,不能指定其长度

        2. 函数头部必须指定 return 子句,函数体内至少要包含一条 return 语句

        3. 可以指定 in 参数,也可以指定 out 参数,以及 in out 参数

        4. 可以为参数指定缺省值。指定缺省值时使用 default 关键字。如 arg1 varchar2 default 'SCOTT'

 

二、使用函数的优点

    1. 增加了代码的灵活性,可以完成一些较为复杂的任务,以及仅仅通过 SQL 无法完成的任务

    2. 可以直接将函数使用到 where 子句中来过滤数据

    3. 可以作为存储过程的参数使用,是存储过程的一种补充

   

三、建立函数

    1. 建立不带参数的函数

        scott@ORCL > create or replace function get_user

          2   return varchar2

          3   is

          4     v_user varchar2 ( 20 );

          5   begin

          6     select username into v_user from user_users ;

          7     return v_user ;

          8   end ;

          9   /

 

        Function created .

 

        -- 使用全局变量接收函数的返回值

            scott@ORCL > var v1 varchar2 ( 20 )  

            scott@ORCL > exec : v1 := get_user

 

            PL / SQL procedure successfully completed .

 

            scott@ORCL > print v1 ;

 

            V1

            --------------------------------

            SCOTT

       

        -- 使用本地变量接收函数的返回值

            scott@ORCL > set serveroutput on ;

            scott@ORCL > declare user_name varchar2 ( 20 );

              2   begin

              3   user_name := get_user ();

              4   dbms_output . put_line ( 'Current user: ' || user_name );

              5   end ;

              6   /

            Current user : SCOTT

 

            PL / SQL procedure successfully completed .    

           

        -- SQL 语句中直接调用函数   

            scott@ORCL > select get_user from dual ;

 

            GET_USER

            ---------------------

            SCOTT   

 

        -- 使用 dbms_output 调用函数 ( 此调用作为存储过程的一个参数来进行调用 )   

            scott@ORCL > set serveroutput on ;

            scott@ORCL > exec dbms_output . put_line ( 'Current user: ' || get_user );

            Current user : SCOTT     

           

    2. 建立带有 in 参数的函数

        scott@ORCL > create or replace function raise_sal ( name in varchar2 )     -- 注意此处定义时参数并为指定类型的长度

          2   return number

          3   as

          4     v_sal emp . sal % type ;

          5   begin

          6     select sal * 1.2 into v_sal from emp

          7     where upper ( ename )= upper ( name );

          8     return v_sal ;

          9   exception

          10     when no_data_found then

          11     raise_application_error (- 20000 , 'Current Employee is not exists' );

          12   end ;

          13   /

 

        Function created .   

 

        scott@ORCL > select sal , raise_sal ( 'SCOTT' ) from emp where ename = 'SCOTT' ;

 

               SAL RAISE_SAL ( 'SCOTT' )

        ---------- ------------------

              3100                3720   

 

        scott@ORCL > select raise_sal ( 'Robinson' ) from dual ;

        select raise_sal ( 'Robinson' ) from dual

               *

        ERROR at line 1 :

        ORA - 20000 : Current Employee is not exists

        ORA - 06512 : at "SCOTT.GET_SAL" , line 11      

 

    3. 建立带有 out 参数的函数

        scott@ORCL > create or replace function get_info

          2   ( name varchar2 , title out varchar2 )

          3   return varchar2

          4   as

          5     deptname dept . dname % type ;

          6   begin

          7     select e . job , d . dname into title , deptname

          8     from emp e inner join dept d

          9       on e . deptno = d . deptno

          10     where upper ( e . ename )= upper ( name );

          11     return deptname ;

          12   exception

          13     when no_data_found then

          14       raise_application_error (- 20000 , 'Current Employee is not exists' );

          15   end ;

          16   /

 

        Function created .

 

        注意对于使用 out 参数的函数,不能使用 SQL 语句来调用。而必须定义变量接收 out 参数和函数的返回值。

        调用如下

        scott@ORCL > var job varchar2 ( 20 );

        scott@ORCL > var dname varchar2 ( 20 );

        scott@ORCL > exec : dname := get_info ( 'scott' ,: job );

 

        PL / SQL procedure successfully completed .

 

        scott@ORCL > print dname job ;

 

        DNAME

        --------------------------------

        RESEARCH

 

 

        JOB

        --------------------------------

        ANALYST

 

    3. 建立带有 in out 参数的函数

        scott@ORCL > create or replace function comp

          2   ( num1 number , num2 in out number )

          3   return number

          4   as

          5     v_result number ( 6 );

          6     v_remainder number ;

          7   begin

          8     v_result := num1 * num2 ;

          9     v_remainder := mod ( num1 , num2 );

          10     num2 := v_remainder ;

          11     return v_result ;

          12   exception

          13     when zero_divide then

          14       raise_application_error (- 20000 , 'Divison by zero' );

          15   end ;

          16   /

 

        Function created .

 

        scott@ORCL > var result1 number ;

        scott@ORCL > var result2 number ;

        scott@ORCL > exec :result2 := 10

 

        PL / SQL procedure successfully completed .

 

        scott@ORCL > exec :result1 := comp ( 16 , :result2 );

 

        PL / SQL procedure successfully completed .

 

        scott@ORCL > print result1 result2 ;

 

           RESULT1

        ----------

               160

 

 

           RESULT2

        ----------

                  6

 

四、函数的调用及限制

    1. 函数的调用 ( 其具体调用方法参照上面的演示 )

        a . 使用全局变量接收函数的返回值

        b . 使用本地变量接受函数的返回值

        c . SQL 语句中直接调用函数

        d . 使用 dbms_output 调用函数

        注:函数在调用的时候需要按位置指定参数,没有存储过程参数传递灵活

            必须具有 execute 函数的权限

   

    2. 函数在 SQL 中调用的主要场合

        由于函数必须要返回数据,因此只能作为表达式的一部分调用。此外函数可以在 SQL 语句的以下部分调用

        a. select 命令的选择列表或子查询中

        b. 条件表达式 where, having 子句中

        c. connect by , start with ,order by 以及 group by 子句中

        d. insert 命令的 values 子句中

        f. update 命令的 set 子句中

       

    3. 函数在 SQL 中调用的限制

        a . SQL 语句中只能调用存储在服务器端的函数,而不能调用存储于客户端的函数

        b. SQL 语句中调用的函数只能带有输入参数 IN ,而不能带有输出参数 OUT 以及输入输出参数 IN OUT

        c. SQL 语句中调用的函数只能使用 SQL 支持的标准数据类型,不能使用 PL/SQL 特有的类型,如 boolean,table,record

        d. SQL 语句中调用的函数不能包含 insert ,update delete 语句

       

        下面演示 SQL 调用时不能完整 DML 操作示例

 

        -- 创建一张表 tb_emp

            scott@ORCL > create table tb_emp as select * from emp ;

 

        -- 创建一个函数,用于删除 tb_emp 表中指定的 empno 号的雇员信息,并返回其薪资

            scott@ORCL > create or replace function delete_oper ( no number )

              2   return number

              3   as

              4     v_sal emp . sal % type ;

              5     begin

              6     select sal into v_sal from tb_emp where empno = no ;

              7     delete from tb_emp where empno = no ;

              8     return v_sal ;

              9     end ;

              10   /

 

            Function created .

       

        -- 使用 SQL 语句调用时,收到了错误信息,在内部查询内不能完成 DML 操作

            scott@ORCL > select delete_oper ( 7788 ) from dual ;

            select delete_oper ( 7788 ) from dual

                   *

            ERROR at line 1 :

            ORA - 14551 : cannot perform a DML operation inside a query

            ORA - 06512 : at "SCOTT.DELETE_OPER" , line 7       

       

        -- 使用 exec 执行时函数被成功执行

            scott@ORCL > var v_no number ;

            scott@ORCL > exec : v_no := delete_oper ( 7788 );

 

            PL / SQL procedure successfully completed .

 

            scott@ORCL > print v_no ;

 

                  V_NO

            ----------

                  3100

 

            scott@ORCL > select * from tb_emp where empno = 7788 ;

 

            no rows selected    

           

        -- 下面的演示表明,不能使用 DML 语句来调用函数

            scott@ORCL > update emp set sal = raise_sal ( 'SCOTT' ) where ename = 'SCOTT' ;

            update emp set sal = raise_sal ( 'SCOTT' ) where ename = 'SCOTT'

                               *

            ERROR at line 1 :

            ORA - 04091 : table SCOTT . EMP is mutating , trigger / function may not see it

            ORA - 06512 : at "SCOTT.RAISE_SAL" , line 6     

           

五、函数的管理  

    函数使用了与存储过程相关的视图,可以从系统视图中获得函数的相关信息

        DBA_OBJECTS

        DBA_SOURCE

        USER_OBJECTS

        USER_SOURCE

 

    -- 查看函数的源码

        scott@ORCL > select text from user_source where name = 'DELETE_OPER' order by line ;

 

        TEXT

        ------------------------------------------------------------

        function delete_oper ( no number )

          return number

          as

          v_sal emp . sal % type ;

          begin

          select sal into v_sal from tb_emp where empno = no ;

          delete from tb_emp where empno = no ;

          commit ;

           return v_sal ;

          end ;

 

    -- 查看函数的参数信息

        scott@ORCL > desc delete_oper ;

        FUNCTION delete_oper RETURNS NUMBER

          Argument Name                   Type                     In/ Out Default ?

          ------------------------------ ----------------------- ------ --------

          NO                              NUMBER                   IN  

 

       

六、函数与存储过程的差异

    存储过程                                              函数

    ----------------------------------                  -------------------------------

    不能被作为表达式调用                                 只能作为表达式被调用

    声明头部关键字为 procedure                         声明头部关键字为 function

    声明头部不包含 return 关键字来描述返回类型          头部必须包含 return 关键字 , PL/SQL 块中至少包含一个有效的 return 语句

    可以通过 out,in out 返回零个或多个值                通过 return 语句返回一个与头部声明中类型一致的值 , 也可使用 in,in out 返回值

    SQL 语句中不可调用存储过程                          SQL 语句可以调用函数

    多用于数据库中完成特定的操作 , 如删除 , 更新 , 插入等 DML 操作      多用于特定的数据如选择等

   

七、更多参考

       

有关 SQL 请参考

        SQL 基础--> 子查询

        SQL 基础--> 多表查询

SQL 基础--> 分组与分组函数

SQL 基础--> 常用函数

SQL 基础--> ROLLUP 与CUBE 运算符实现数据汇总

SQL 基础--> 层次化查询(START BY ... CONNECT BY PRIOR)

 

    有关 PL/SQL 请参考

        PL/SQL --> 语言基础

PL/SQL --> 流程控制

PL/SQL --> 存储过程

PL/SQL --> 函数

PL/SQL --> 游标

PL/SQL --> 隐式游标(SQL%FOUND)

PL/SQL --> 异常处理(Exception)

PL/SQL --> PL/SQL 记录

PL/SQL --> 包的创建与管理

PL/SQL --> 包重载、初始化

PL/SQL --> DBMS_DDL 包的使用

PL/SQL --> DML 触发器

PL/SQL --> INSTEAD OF 触发器

 

   

PL/SQL --> 函数


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论