PLSQLOracle函数与索引

Posted David Wu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PLSQLOracle函数与索引相关的知识,希望对你有一定的参考价值。

本篇主要内容如下:

6.1 引言

6.2 创建函数

6.3 存储过程

6.3.1创建过程

6.3.2调用存储过程

6.3.3 AUTHID

6.3.4 PRAGMA AUTONOMOUS_TRANSACTION

6.3.5开发存储过程步骤

6.3.6删除过程和函数

6.3.7过程与函数的比较


 

6.1 引言

过程与函数(另外还有包与触发器)是命名的PL/SQL块(也是用户的方案对象),被编译后存储在数据库中,以备执行。因此,其它PL/SQL块可以按名称来使用他们。所以,可以将商业逻辑、企业规则写成函数或过程保存到数据库中,以便共享。

过程和函数统称为PL/SQL子程序,他们是被命名的PL/SQL块,均存储在数据库中,并通过输入、输出参数或输入/输出参数与其调用者交换信息。过程和函数的唯一区别是函数总向调用者返回数据,而过程则不返回数据。在本节中,主要介绍:

1.   创建存储过程和函数。

2.   正确使用系统级的异常处理和用户定义的异常处理。

3.   建立和管理存储过程和函数。

6.2 创建函数

1. 创建函数

语法如下:

CREATE [OR REPLACE] FUNCTION function_name (arg1 [ { IN | OUT | IN OUT }] type1 [DEFAULT value1], [arg2 [ { IN | OUT | IN OUT }] type2 [DEFAULT value1]], ...... [argn [ { IN | OUT | IN OUT }] typen [DEFAULT valuen]]) [ AUTHID DEFINER | CURRENT_USER ] RETURN return_type 
IS|AS     
<类型.变量的声明部分>
BEGIN     
<执行部分>     RETURN expression 
EXCEPTION     异常处理部分 
END function_name;

l         IN,OUT,IN OUT是形参的模式。若省略,则为IN模式。IN模式的形参只能将实参传递给形参,进入函数内部,但只能读不能写,函数返回时实参的值不变。OUT模式的形参会忽略调用时的实参值(或说该形参的初始值总是NULL),但在函数内部可以被读或写,函数返回时形参的值会赋予给实参。IN OUT具有前两种模式的特性,即调用时,实参的值总是传递给形参,结束时,形参的值传递给实参。调用时,对于IN模式的实参可以是常量或变量,但对于OUTIN OUT模式的实参必须是变量。

 

l         一般,只有在确认function_name函数是新函数或是要更新的函数时,才使用OR REPALCE关键字,否则容易删除有用的函数。

 

例1.           获取某部门的工资总和:

 

--获取某部门的工资总和
CREATE OR REPLACE FUNCTION get_salary(Dept_no NUMBER,Emp_count OUT NUMBER)   RETURN NUMBER 
IS   
  V_sum NUMBER; 
BEGIN   
  SELECT  SUM(SALARY), count(*) INTO V_sum, emp_count     
     FROM EMPLOYEES 
        WHERE DEPARTMENT_ID=dept_no;   
  RETURN v_sum; 
EXCEPTION    
  WHEN NO_DATA_FOUND THEN       
     DBMS_OUTPUT.PUT_LINE(\'你需要的数据不存在!\');    
  WHEN OTHERS THEN       
     DBMS_OUTPUT.PUT_LINE(SQLCODE||\'---\'||SQLERRM); 
END get_salary;

2. 函数的调用

函数声明时所定义的参数称为形式参数,应用程序调用时为函数传递的参数称为实际参数。应用程序在调用函数时,可以使用以下三种方法向函数传递参数:

 

第一种参数传递格式:位置表示法。

即在调用时按形参的排列顺序,依次写出实参的名称,而将形参与实参关联起来进行传递。用这种方法进行调用,形参与实参的名称是相互独立,没有关系,强调次序才是重要的。

格式为:

       argument_value1[,argument_value2 …]

 

2计算某部门的工资总和:

DECLARE   
  V_num NUMBER;   
  V_sum NUMBER; 
BEGIN   
  V_sum :=get_salary(10, v_num);   
  DBMS_OUTPUT.PUT_LINE(\'部门号为:10的工资总和:\'||v_sum||\',人数为:\'||v_num); 
END;

第二种参数传递格式:名称表示法。

即在调用时按形参的名称与实参的名称,写出实参对应的形参,而将形参与实参关联起来进行传递。这种方法,形参与实参的名称是相互独立的,没有关系,名称的对应关系才是最重要的,次序并不重要。

格式为:

       argument => parameter [,…]

其中:argument 为形式参数,它必须与函数定义时所声明的形式参数名称相同parameter 为实际参数。

在这种格式中,形势参数与实际参数成对出现,相互间关系唯一确定,所以参数的顺序可以任意排列。

3计算某部门的工资总和:

 

DECLARE   
  V_num NUMBER;     
  V_sum NUMBER; 
BEGIN     
  V_sum :=get_salary(emp_count => v_num, dept_no =>10);
  DBMS_OUTPUT.PUT_LINE(\'部门号为:10的工资总和:\'||v_sum||\',人数为:\'||v_num); 
END;

 

 

 

第三种参数传递格式:组合传递。

即在调用一个函数时,同时使用位置表示法和名称表示法为函数传递参数。采用这种参数传递方法时,使用位置表示法所传递的参数必须放在名称表示法所传递的参数前面。也就是说,无论函数具有多少个参数,只要其中有一个参数使用名称表示法,其后所有的参数都必须使用名称表示法。

4

 

--注意VARCHAR2不能给精度,如:VARCHAR2(10),其它类似 Age INTEGER, 
CREATE OR REPLACE FUNCTION demo_fun(Name VARCHAR2, Sex VARCHAR2)   RETURN VARCHAR2
AS   
  V_var VARCHAR2(32); 
BEGIN   
  V_var := name||\'\'||TO_CHAR(age)||\'岁.\'||sex;   
  RETURN v_var; 
END;

DECLARE   
  VarVARCHAR(32); 
BEGIN   
  Var := demo_fun(\'user1\', 30, sex =>\'\');   
  DBMS_OUTPUT.PUT_LINE(var);
  Var := demo_fun(\'user2\', age =>40, sex =>\'\');     
  DBMS_OUTPUT.PUT_LINE(var);
  Var := demo_fun(\'user3\', sex =>\'\', age =>20);     
  DBMS_OUTPUT.PUT_LINE(var); 
END;

 

无论采用哪一种参数传递方法,实际参数和形式参数之间的数据传递只有两种方法:传址法和传值法。所谓传址法是指在调用函数时,将实际参数的地址指针传递给形式参数,使形式参数和实际参数指向内存中的同一区域,从而实现参数数据的传递。这种方法又称作参照法,即形式参数参照实际参数数据。输入参数均采用传址法传递数据。

       传值法是指将实际参数的数据拷贝到形式参数,而不是传递实际参数的地址。默认时,输出参数和输入/输出参数均采用传值法。在函数调用时,ORACLE将实际参数数据拷贝到输入/输出参数,而当函数正常运行退出时,又将输出形式参数和输入/输出形式参数数据拷贝到实际参数变量中。

 

3. 参数默认值

CREATE OR REPLACE FUNCTION 语句中声明函数参数时可以使用DEFAULT关键字为输入参数指定默认值。

 

5

 

CREATE OR REPLACE FUNCTION demo_fun(Name VARCHAR2,Age INTEGER,   Sex VARCHAR2DEFAULT\'\')   RETURN VARCHAR2
AS   
  V_var VARCHAR2(32); 
BEGIN   
  V_var := name||\'\'||TO_CHAR(age)||\'岁.\'||sex;   
  RETURN v_var; 
END;

具有默认值的函数创建后,在函数调用时,如果没有为具有默认值的参数提供实际参数值,函数将使用该参数的默认值。但当调用者为默认参数提供实际参数时,函数将使用实际参数值。在创建函数时,只能为输入参数设置默认值,而不能为输入/输出参数设置默认值。

DECLARE

  varVARCHAR(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;

6.3 存储过程

6.3.1创建过程

 

建立存储过程

ORACLE SERVER上建立存储过程,可以被多个应用程序调用,可以向存储过程传递参数,也可以向存储过程传回参数.

 

创建过程语法:

 

CREATE [OR REPLACE] PROCEDURE procedure_name ([arg1 [ IN | OUT | IN OUT ]] type1 [DEFAULT value1], [arg2 [ IN | OUT | IN OUT ]] type2 [DEFAULT value1]], ...... [argn [ IN | OUT | IN OUT ]] typen [DEFAULT valuen])     [ AUTHID DEFINER | CURRENT_USER ] 
 IS|AS    
  <声明部分>
BEGIN   
  <执行部分> 
EXCEPTION   
  <可选的异常错误处理程序>
END procedure_name;

 

 

 

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

 

6用户连接登记记录;

CREATE TABLE logtable (userid VARCHAR2(10), logdate date);

CREATE OR REPLACE PROCEDURE logexecution 
IS 
BEGIN 
  INSERT INTO logtable (userid, logdate) 
    VALUES (USER, SYSDATE); 
END;

7删除指定员工记录;

CREATE OR REPLACE PROCEDURE DelEmp (v_empno IN employees.employee_id%TYPE) 
AS 
  No_result EXCEPTION; 
BEGIN    
  DELETEFROM employees 
    WHERE employee_id = v_empno;    
  IF SQL%NOTFOUND THEN       
    RAISE no_result;    
  ENDIF;   
  DBMS_OUTPUT.PUT_LINE(\'编码为\'||v_empno||\'的员工已被删除!\'); 
EXCEPTION    
  WHEN no_result THEN       
    DBMS_OUTPUT.PUT_LINE(\'温馨提示:你需要的数据不存在!\');    
  WHEN OTHERS THEN       
    DBMS_OUTPUT.PUT_LINE(SQLCODE||\'---\'||SQLERRM); 
END DelEmp;

8插入员工记录:

 

CREATE OR REPLACE PROCEDURE InsertEmp(v_empno in employees.employee_id%TYPE,  v_firstname in employees.first_name%TYPE,    v_lastname  in employees.last_name%TYPE,    v_deptno in employees.department_id%TYPE    ) 
AS    
  empno_remaining EXCEPTION;    
  PRAGMA EXCEPTION_INIT(empno_remaining, -1);   
   /* -1 是违反唯一约束条件的错误代码 */
BEGIN    
  INSERT INTO EMPLOYEES(EMPLOYEE_ID, FIRST_NAME, LAST_NAME, HIRE_DATE,DEPARTMENT_ID)    VALUES(v_empno, v_firstname,v_lastname, sysdate, v_deptno);    
  DBMS_OUTPUT.PUT_LINE(\'温馨提示:插入数据记录成功!\'); 
EXCEPTION    
  WHEN empno_remaining THEN       
     DBMS_OUTPUT.PUT_LINE(\'温馨提示:违反数据完整性约束!\');    
  WHEN OTHERS THEN       
     DBMS_OUTPUT.PUT_LINE(SQLCODE||\'---\'||SQLERRM); 
END InsertEmp;

9使用存储过程向departments表中插入数据。

 

CREATE OR REPLACE PROCEDURE insert_dept   (v_dept_id IN departments.department_id%TYPE,    v_dept_name IN departments.department_name%TYPE,    v_mgr_id IN departments.manager_id%TYPE,    v_loc_id IN departments.location_id%TYPE) 
IS  
  ept_null_error EXCEPTION;  
  PRAGMA EXCEPTION_INIT(ept_null_error, -1400);  
  ept_no_loc_id EXCEPTION;  
  PRAGMA EXCEPTION_INIT(ept_no_loc_id, -2291); 
BEGIN  
  INSERT INTO departments  (department_id, department_name, manager_id, location_id)    VALUES    (v_dept_id, v_dept_name, v_mgr_id, v_loc_id);    
  DBMS_OUTPUT.PUT_LINE(\'插入部门\'||v_dept_id||\'成功\'); 
EXCEPTION    
  WHEN DUP_VAL_ON_INDEX THEN        
    RAISE_APPLICATION_ERROR(-20000, \'部门编码不能重复\');    
  WHEN ept_null_error THEN       
    RAISE_APPLICATION_ERROR(-20001, \'部门编码、部门名称不能为空\');      
  WHEN ept_no_loc_id THEN       
    RAISE_APPLICATION_ERROR(-20002, \'没有该地点\'); 
END insert_dept;

/*调用实例一:
DECLARE    
  ept_20000 EXCEPTION;    
  PRAGMA EXCEPTION_INIT(ept_20000, -20000);    
  ept_20001 EXCEPTION;    
  PRAGMA EXCEPTION_INIT(ept_20001, -20001);    
  ept_20002 EXCEPTION;  
  PRAGMA EXCEPTION_INIT(ept_20002, -20002); 
BEGIN    
  insert_dept(300, \'部门300\', 100, 2400);    
  insert_dept(310, NULL, 100, 2400);    
  insert_dept(310, \'部门310\', 100, 900); 
EXCEPTION    
  WHEN ept_20000 THEN       
    DBMS_OUTPUT.PUT_LINE(\'ept_20000部门编码不能重复\');    
  WHEN ept_20001 THEN       
    DBMS_OUTPUT.PUT_LINE(\'ept_20001部门编码、部门名称不能为空\');    
  WHEN ept_20002 THEN       
    DBMS_OUTPUT.PUT_LINE(\'ept_20002没有该地点\');    
  WHEN OTHERS THEN       
    DBMS_OUTPUT.PUT_LINE(\'others出现了其他异常错误\'); 
END;

调用实例二: 
DECLARE    
  ept_20000 EXCEPTION;    
  PRAGMA EXCEPTION_INIT(ept_20000, -20000);    
  ept_20001 EXCEPTION;    
  PRAGMA EXCEPTION_INIT(ept_20001, -20001);    
  ept_20002 EXCEPTION;    
  PRAGMA EXCEPTION_INIT(ept_20002, -20002); 
BEGIN    
  insert_dept(v_dept_name => \'部门310\', v_dept_id => 310,                v_mgr_id => 100, v_loc_id => 2400);    
  insert_dept(320, \'部门320\', v_mgr_id => 100, v_loc_id => 900); EXCEPTION    
  WHEN ept_20000 THEN       
    DBMS_OUTPUT.PUT_LINE(\'ept_20000部门编码不能重复\');    
  WHEN ept_20001 THEN       
    DBMS_OUTPUT.PUT_LINE(\'ept_20001部门编码、部门名称不能为空\');    
  WHEN ept_20002 THEN       
    DBMS_OUTPUT.PUT_LINE(\'ept_20002没有该地点\');    
  WHEN OTHERS THEN       
    DBMS_OUTPUT.PUT_LINE(\'others出现了其他异常错误\'); END;
 */

 

 

 

6.3.2调用存储过程

 

   存储过程建立完成后,只要通过授权,用户就可以在SQLPLUS ORACLE开发工具或第三方开发工具中来调用运行。对于参数的传递也有三种:按位置传递、按名称传递和组合传递,传递方法与函数的一样。ORACLE 使用EXECUTE 语句来实现对存储过程的调用:

 

EXEC[UTE] procedure_name( parameter1, parameter2…);

 

10

 

EXECUTE logexecution;

 

11查询指定员工记录;

CREATE OR REPLACE PROCEDURE QueryEmp (v_empno IN  employees.employee_id%TYPE, v_ename OUT employees.first_name%TYPE, v_sal   OUT employees.salary%TYPE)  
AS
BEGIN        
  SELECT last_name || last_name, salary INTO v_ename, v_sal     
    FROM employees     
      WHERE employee_id = v_empno;        
  DBMS_OUTPUT.PUT_LINE(\'温馨提示:编码为\'||v_empno||\'的员工已经查到!\'); EXCEPTION        
  WHEN NO_DATA_FOUND THEN       
    DBMS_OUTPUT.PUT_LINE(\'温馨提示:你需要的数据不存在!\');       
  WHEN OTHERS THEN       
    DBMS_OUTPUT.PUT_LINE(SQLCODE||\'---\'||SQLERRM); 
END QueryEmp; 
--调用
DECLARE     
  v1 employees.first_name%TYPE;     
  v2 employees.salary%TYPE; 
BEGIN    
  QueryEmp(100, v1, v2);    
  DBMS_OUTPUT.PUT_LINE(\'姓名:\'||v1);    
  DBMS_OUTPUT.PUT_LINE(\'工资:\'||v2);    
  QueryEmp(103, v1, v2);    
  DBMS_OUTPUT.PUT_LINE(\'姓名:\'||v1);    
  DBMS_OUTPUT.PUT_LINE(\'工资:\'||v2);    
  QueryEmp(104, v1, v2);    
  DBMS_OUTPUT.PUT_LINE(\'姓名:\'||v1);    
  DBMS_OUTPUT.PUT_LINE(\'工资:\'||v2);
END;

 

12计算指定部门的工资总和,并统计其中的职工数量。

 

CREATE OR REPLACE PROCEDURE proc_demo (   dept_no NUMBERDEFAULT10,     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 关键字。

 

13建立本地过程,用于计算指定部门的工资总和,并统计其中的职工数量;

DECLARE 
  V_num NUMBER; 
  V_sum NUMBER(8, 2); 
  PROCEDURE proc_demo   (     Dept_no NUMBERDEFAULT10,     Sal_sum OUT NUMBER,     Emp_count OUT NUMBER   ) 
  IS
  BEGIN     
    SELECTSUM(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;
--调用方法:
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;

 

6.3.3 AUTHID

以上是关于PLSQLOracle函数与索引的主要内容,如果未能解决你的问题,请参考以下文章

PLSQLOracle中的异常

solr分布式索引实战分片配置读取:工具类configUtil.java,读取配置代码片段,配置实例

java.lang.IllegalStateException:键 f0 的片段不再存在:索引 1

PLSQL ORACLE:表变量之间的内连接

javascript UV Index Monitor App订阅PubNub并显示UV索引值。博文的代码片段。在这里查看项目:https:// githu

c_cpp UV Index Indicator订阅PubNub并使用颜色显示UV索引值。博文的代码片段。在这里查看项目:https:/