6.2 创建函数
    1. 创建函数
    语法如下:

    1. CREATE [OR REPLACE] FUNCTION function_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. RETURN return_type
    8. IS | AS
    9. --<类型.变量的声明部分>
    10. BEGIN
    11. -- 执行部分
    12. RETURN expression
    13. EXCEPTION
    14. -- 异常处理部分
    15. END function_name;

    IN,OUT,IN OUT是形参的模式。若省略,则为IN模式。IN模式的形参只能将实参传递给形参,进入函数内部,但只能读不能写,函数返回时实参的值不变。OUT模式的形参会忽略调用时的实参值(或说该形参的初始值总是NULL),但在函数内部可以被读或写,函数返回时形参的值会赋予给实参。IN OUT具有前两种模式的特性,即调用时,实参的值总是传递给形参,结束时,形参的值传递给实参。调用时,对于IN模式的实参可以是常量或变量,但对于OUT和IN OUT模式的实参必须是变量。
    一般,只有在确认function_name函数是新函数或是要更新的函数时,才使用OR REPALCE关键字,否则容易删除有用的函数。
    例1. 获取某部门的工资总和:
    1 —获取某部门的工资总和

    1. CREATE OR REPLACE
    2. FUNCTION get_salary(Dept_no NUMBER,Emp_count OUT NUMBER)
    3. RETURN NUMBER
    4. IS
    5. V_sum NUMBER;
    6. BEGIN
    7. SELECT SUM(SALARY), count(*) INTO V_sum, emp_count
    8. FROM EMPLOYEES WHERE DEPARTMENT_ID=dept_no;
    9. RETURN v_sum;
    10. EXCEPTION
    11. WHEN NO_DATA_FOUND THEN
    12. DBMS_OUTPUT.PUT_LINE('你需要的数据不存在!');
    13. WHEN OTHERS THEN
    14. DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
    15. END get_salary;
    1. 函数的调用
      函数声明时所定义的参数称为形式参数,应用程序调用时为函数传递的参数称为实际参数。应用程序在调用函数时,可以使用以下三种方法向函数传递参数:
      第一种参数传递格式:位置表示法。
      即在调用时按形参的排列顺序,依次写出实参的名称,而将形参与实参关联起来进行传递。用这种方法进行调用,形参与实参的名称是相互独立,没有关系,强调次序才是重要的。
      格式为:
      argument_value1[,argument_value2 …]
      例2:计算某部门的工资总和:
      1 DECLARE
      2 V_num NUMBER;
      3 V_sum NUMBER;
      4 BEGIN
      5 V_sum :=get_salary(10, v_num);
      6 DBMS_OUTPUT.PUT_LINE(‘部门号为:10的工资总和:’||v_sum||’,人数为:’||v_num);
      7 END;
      第二种参数传递格式:名称表示法。
      即在调用时按形参的名称与实参的名称,写出实参对应的形参,而将形参与实参关联起来进行传递。这种方法,形参与实参的名称是相互独立的,没有关系,名称的对应关系才是最重要的,次序并不重要。
      格式为:
      argument => parameter [,…]
      其中:argument 为形式参数,它必须与函数定义时所声明的形式参数名称相同parameter 为实际参数。
      在这种格式中,形势参数与实际参数成对出现,相互间关系唯一确定,所以参数的顺序可以任意排列。
      例3:计算某部门的工资总和:
      1 DECLARE
      2 V_num NUMBER;
      3 V_sum NUMBER;
      4 BEGIN
      5 V_sum :=get_salary(emp_count => v_num, dept_no => 10);
      6 DBMS_OUTPUT.PUT_LINE(‘部门号为:10的工资总和:’||v_sum||’,人数为:’||v_num);
      7 END;
      第三种参数传递格式:组合传递。
      即在调用一个函数时,同时使用位置表示法和名称表示法为函数传递参数。采用这种参数传递方法时,使用位置表示法所传递的参数必须放在名称表示法所传递的参数前面。也就是说,无论函数具有多少个参数,只要其中有一个参数使用名称表示法,其后所有的参数都必须使用名称表示法。
      例4:
      1. CREATE OR REPLACE FUNCTION demo_fun(
      2. Name VARCHAR2,--注意VARCHAR2不能给精度,如:VARCHAR2(10),其它类似
      3. Age INTEGER,
      4. Sex VARCHAR2)
      5. RETURN VARCHAR2
      6. AS
      7. V_var VARCHAR2(32);
      8. BEGIN
      9. V_var := name||':'||TO_CHAR(age)||'岁.'||sex;
      10. RETURN v_var;
      11. END;
      12. DECLARE
      13. Var VARCHAR(32);
      14. BEGIN
      15. Var := demo_fun('user1', 30, sex => '男');
      16. DBMS_OUTPUT.PUT_LINE(var);
      17. Var := demo_fun('user2', age => 40, sex => '男');
      18. DBMS_OUTPUT.PUT_LINE(var);
      19. Var := demo_fun('user3', sex => '女', age => 20);
      20. DBMS_OUTPUT.PUT_LINE(var);
      21. END;
      无论采用哪一种参数传递方法,实际参数和形式参数之间的数据传递只有两种方法:传址法和传值法。所谓传址法是指在调用函数时,将实际参数的地址指针传递给形式参数,使形式参数和实际参数指向内存中的同一区域,从而实现参数数据的传递。这种方法又称作参照法,即形式参数参照实际参数数据。输入参数均采用传址法传递数据。
      传值法是指将实际参数的数据拷贝到形式参数,而不是传递实际参数的地址。默认时,输出参数和输入/输出参数均采用传值法。在函数调用时,ORACLE将实际参数数据拷贝到输入/输出参数,而当函数正常运行退出时,又将输出形式参数和输入/输出形式参数数据拷贝到实际参数变量中。
      3. 参数默认值
      在CREATE OR REPLACE FUNCTION 语句中声明函数参数时可以使用DEFAULT关键字为输入参数指定默认值。
      例5:
      CREATE OR REPLACE FUNCTION demo_fun(
      Name VARCHAR2,
      Age INTEGER,
      Sex VARCHAR2 DEFAULT '男')
      RETURN VARCHAR2
      AS
      V_var VARCHAR2(32);
      BEGIN
      V_var := name||':'||TO_CHAR(age)||'岁.'||sex;
      RETURN v_var;
      END;
      
      具有默认值的函数创建后,在函数调用时,如果没有为具有默认值的参数提供实际参数值,函数将使用该参数的默认值。但当调用者为默认参数提供实际参数时,函数将使用实际参数值。在创建函数时,只能为输入参数设置默认值,而不能为输入/输出参数设置默认值。
      DECLARE
      var VARCHAR(32);
      BEGIN
      Var := demo_fun(‘user1’, 30);
      DBMS_OUTPUT.PUT_LINE(var);
      Var := demo_fun(‘user2’, age => 40);
      DBMS_OUTPUT.PUT_LINE(var);
      Var := demo_fun(‘user3’, sex => ‘女’, age => 20);
      DBMS_OUTPUT.PUT_LINE(var);
      END;