美文网首页程序园
Oracle SQL 学习笔记21 - Procedure 和

Oracle SQL 学习笔记21 - Procedure 和

作者: 赵阳_c149 | 来源:发表于2020-02-08 17:26 被阅读0次

    Oracle数据库支持创建和使用子程序。创建子程序有很多优点:

    1. 便于维护
    2. 提高数据处理的安全性和一致性
    3. 提高数据处理性能
    4. 增强代码的清晰透明性
      Oracle支持的子程序有两类:
    • 存储过程 (procedure)
    • 函数(function)

    在PL/SQL中创建和使用procedure

    定义

    存储过程是一种执行动作的子程序,可以保存为一种模式对象。创建存储过程提升了代码的可充用和可维护性。

    语法

    CREATE  [OR  REPLACE]  PROCEDURE  procedure_name
    [(parameter1  [mode]  datatype1,
     parameter2  [mode]  datatype2,  ...)]
    IS|AS
      [local1_variable_declarations;...]
    BEGIN
      -- actions;
    END  [procedure_name];
    

    开发Procedure

    pro_dev.JPG

    参数

    参数定义于子程序的头部,在调用者和子程序之间传递数据。有三种类型:

    1. IN parameter:默认类型,表示传入参数
    2. OUT parameter:传出参数
    3. IN OUT:传入传出参数
    CREATE  PROCEDURE  procedure(param  [mode]  datatype)
    
    Formal 和 Actual 参数
    • Formal parameter
      在子程序定义部分声明的一种本地变量
    CREATE  PROCEDURE  raise_sal(id  NUMBER,  sal  NUMBER)  IS
    BEGIN  ...
    END  raise_sal;
    
    • Actual parameters
      可以是具体的值也可以是主程序的变量
    emp_id  :=  100;
    raise_sal(emp_id,  2000)
    
    使用IN Parameter 举例
    CREATE  OR  REPLACE  PROCEDURE  raise_salary  (id  IN  employees.employee_id%TYPE,  percent  IN  NUMBER)
    IS
    BEGIN
      UPDATE  employees
      SET  salary  =  salary  *  (1  +  percent/100)
      WHERE  employee_id  =  id;
    END  raise_salary;
    /
    
    EXECUTE  raise_salary(176,  10)
    
    使用OUT Parameter 举例
    CREATE  OR  REPLACE  PROCEDURE  query_emp
    (id  IN  employees.employee_id%TYPE,
     name OUT  employees.last_name%TYPE,
     salary  OUT  employees.salary%TYPE)
    BEGIN
      SELECT  last_name,  salary  INTO  name,  salary
      FROM  employees
      WHERE  employee_id  =  id;
    END  query_emp;
    
    OUT Parameters 的值

    可以用 DBMS_OUTPUT.PUT_LINE 打印变量。

    SET  SERVEROUTPUT  ON
    DECLARE
      emp_name  employees.last_name%TYPE;
      emp_sal  employees.salary%TYPE;
    BEGIN
      query_emp(171,  emp_name,  emp_sal);
      DBMS_OUTPUT.PUT_LINE('Name:  '  ||  emp_name);
      DBMS_OUTPUT.PUT_LINE('Salary:  '  ||  emp_sal);
    END;
    

    也可以用SQL * PLUS host variables 打印变量

    VARIABLE  name  VARCHAR2(25)
    VARIABLE  sal  NUMBER
    EXECUTE  query_emp(171,  :name,  :sal)
    PRINT  name  sal
    
    使用 Host Variables

    Host Variable 又称“bind”或者“global”变量。定义于PL/SQL之外,可以通过下列方式定义:

    • SQL * Plus VARIABLE 命令
    • Oracle Forms internal 和 UI variables
    • Java variables

    引用host variables需要在变量名称前加上“:”。Host Variable 可以在匿名块引用但是不能在过程内部引用,也可以作为参数传入传出过程。

    使用IN OUT Parameter 举例

    调用环境:

    phone_no 
    # 在调用之前为‘8006330575’
    # 在调用之前为‘(800)633-0575’
    
    CREATE  OR  REPLACE  PROCEDURE  format_phone
      (phone_no  IN  OUT  VARCHAR2)  IS
    BEGIN
      phone_no  :=  '('  ||  SUBSTR(phone_no,  1,  3)  ||
                    ')'  ||  SUBSTR(phone_no,  4,  4)  ||
                    '-'  ||  SUBSTR(phone_no,  7);
    END  format_phone;
    /
    

    传递参数的方式

    • 位置传参(Positional)
      将 Actual 参数按照 Formal 参数的顺序列出。
    • 名称参数(Named)
      Actual 参数可以以任意顺序列出,用 association 操作符(=>)将 Formal 参数和相关的 Actual 参数联系起来。
    • 复合模式(Combination)
      一些参数以位置方式传入,其他的以名称方式传入。
    传参举例
    CREATE  OR  REPLACE  PROCEDURE  add_dept(
      name  IN  departments.department_name%TYPE,
      loc  IN  departments.location_id%TYPE)  IS
    BEGIN
      INSERT  INTO  departments(department_id,  departmemt_name,  location_id)
      VALUES  (departments_seq.NEXTVAL,  name,  loc);
    END  add_dept;
    /
    
    EXECUTE  add_dept('TRAINING',  2500)
    EXECUTE  add_dept(loc=>2400,  name=>'EDUCATION')
    
    传参时使用 DEFAULT 选项
    CREATE  OR  REPLACE  PROCEDURE  add_dept(
      name  IN  departments.department_name%TYPE  :=  'Unknown',
      loc  IN  departments.location_id%TYPE  DEFAULT  1700)  
    IS
    BEGIN
      INSERT  INTO  departments(department_id,  departmemt_name,  location_id)
      VALUES  (departments_seq.NEXTVAL,  name,  loc);
    END  add_dept;
    /
    

    有了default,传参方式更加灵活

    EXECUTE  add_dept
    EXECUTE  add_dept('ADVERTISING',  loc  =>  1200)
    EXECUTE  add_dept(loc  =>  1200)
    

    传参模式总结

    IN OUT IN OUT
    Default 模式 必须指定 必须指定
    值被传入子程序 返回值到调用子程序的环境 被传入子程序,返回值到调用子程序的环境
    Formal 参数作为一个常量(constant) 没有被初始化的Variable 初始化的Variable
    Actual 参数可以是一个literal,表达式,常量,或者被初始化的Variable 必须是一个Variable 必须是一个Variable
    可以被赋Default值 不能被赋Default值 不能被赋Default值

    调用Procedures

    可以在匿名块中调用存储过程,也可以在其他存储过程中调用存储过程。

    CREATE  OR  REPLACE  PROCEDURE  process_employees
    IS
      CURSOR  emp_cursor  IS
        SELECT  employee_id
        FROM  employees;
    BEGIN
      FOR  emp_rec  IN  emp_cursor
      LOOP
        raise_salary(emp_rec.employee_id,  10);
      END  LOOP;
      COMMIT;
    END  process_employees;
    /
    

    异常处理

    EXP.JPG
    • 异常处理举例
    CREATE  PROCEDURE  add_department(
      name  VARCHAR2,  mgr  NUMBER,  loc  NUMBER)  IS
    BEGIN
      INSERT  INTO  DEPARTMENTS  (department_id,  department_name,  manager_id,  location_id)
      VALUES  (DEPARTMENTS_SEQ.NEXTVAL,  name,  mgr,  loc);
      DBMS_OUTPUT.PUT_LINE('Added  Dept:  '||  name);
    EXCEPTION
      WHEN  OTHERS  THEN
        DBMS_OUTPUT.PUT_LINE('Err:  adding  dept:  '||  name);
    END;
    /
    
    CREATE  PROCEDURE  create_departments  IS
    BEGIN
      add_department('Media',  100,  1800); # ok
      add_department('Editing',  99,  1800);  # error
      add_department('Advertising',  101,  1800); #ok
    END;
    

    删除Procedures

    DROP  PROCEDURE  procedure_name;
    

    通过数据字典查看 procedure

    可以通过两种方式在字典中查看存储过程:

    • 通过USER_SOURCE看代码
    SELECT  text
    FROM  user_source
    WHERE  name  =  'ADD_DEPARTMENT' and type  =  'PROCEDURE'
    ORDER  BY  line;
    
    • 通过USER_OBJECTS看名称和创建时间
    SELECT  object_name
    FROM  user_objects
    WHERE  object_type  =  'PROCEDURE';
    

    在PL/SQL中创建和使用function

    创建Functions的语法

    创建Functions必须要有RETURN statement:

    CREATE  [OR  REPLACE]  FUNCTION  function_name
      [(parameter1  [mode1]  datetype1,  ...)]
    RETURN  datatype  IS|AS
      [local_variable_declarations;  ...]
    BEGIN
      --  actions;
      RETURN  expression;
    END  [function_name];
    

    Stored Function 举例

    • 创建函数
    CREATE  OR  REPLACE  FUNCTION  get_sal(
      id employees.employee_id%TYPE)  
    RETURN  NUMBER  IS
      sal  employees.salary%TYPE  :=  0;
    BEGIN
      SELECT  sal
      INTO  sal
      FROM  employees
      WHERE  employee_id  =  id;
      RETURN  sal;
    END  get_sal;
    /
    
    EXECUTE  dbms_output.put_line(get_sal(100))
    

    函数的执行方法

    作为PL/SQL 表达式的一部分

    • 用 host variable 来获得结果
    VARIABLE  salary  NUMBER
    EXECUTE  :salary :=  get_sal(100)
    
    • 使用local variable 来获得结果
    DECLARE  sal  employees.salary%TYPE;
    BEGIN
      sal  :=  get_sal(100);...
    END;
    

    作为参数传入另一个子程序

    EXECUTE  dbms_output.put_line(get_sal(100))
    

    在SQL语句中使用(有一些限制)

    SELECT  job_id,  get_sal(employee_id)  FROM  employees;
    

    在SQL中使用用户自定义函数的好处

    在SQL中使用用户自定义函数有很多好处:

    1. 当活动过于复杂的时候,能扩展SQL
    2. 较之于在应用中filter数据,用自定义函数在WHERE子句filter数据更有效率
    3. 能操作数据的值

    在SQL中使用函数举例

    CREATE  OR  REPLACE  FUNCTION  tax(value  IN  NUMBER)
    RETURN  NUMBER  IS
    BEGIN
      RETRUN  (value  *  0.08);
    END  tax;
    /
    SELECT  employee_id,  last_name,  salary,  tax(salary)
    FROM  employees
    WHERE  department_id  =  100;
    

    哪些子句中可以调用函数

    用户自定义函数和Oracle预定义函数可用于:

    1. 查询中SELECT的列表或者SELECT子句
    2. WHERE子句和HAVING子句中的条件表达式
    3. 查询中的子句:CONNECT BY,START WITH,ORDER BY和GROUP BY
    4. INSERT语句中的VALUES子句
    5. UPDATE语句的SET子句

    通过SQL调用函数的限制

    通过SQL表达式调用函数的限制:

    • 函数必须创建函数对象
    • 仅可接受IN参数而且只能是SQL data types,而非

    PL/SQL-specific类型

    • 返回SQL数据类型,而非PL/SQL-specific类型
      通过SQL语句中调用函数的限制
    • 必须以位置模式传递参数
    • 调用者或是函数属主或有执行权限
      函数如果通过
    • SELECT 或并行UPDATE,DELETE语句调用,则函数不能包含DML
    • 针对表T的UPDATE或DELETE语句调用,则函数不能包括任何针对表T的任何SELECT和DML
    • SQL语句调用,则函数不可结束事务(that is, cannot execute COMMIT or ROLLBACK operations),不可定义或使用savepoint,不可alter system或session。

    调用函数限制举例

    CREATE  OR  REPLACE  FUNCTION  dml_call_sql(sal  NUMBER)
    RETURN  NUMBER  IS
    BEGIN
      INSERT  INTO  employees(employee_id,  last_name,  email,  hire_date,  job_id,  salary)
      VALUES(1,  'Frost',  'jfrost@company.com',  SYSDATE,  'SA_MAN',  sal);
      RETRUN  (sal  +  100)
    END;
    

    以下语句会抛出异常:

    UPDATE  employees
      SET  salary  =  dml_call_sql(2000)
    WHERE  employee_id  =  170;
    # ORA-04091...
    # ORA-06512...
    

    删除Functions

    删除一个已经保存的函数

    DROP  FUNCTION  function_name
    
    • 删除函数之后,所有赋予函数的权限将被收回。
    • CREATE OR REPLAE 等同于删除函数,然后重建该函数,函数上的权限不变。

    通过数据字典查询函数信息

    • 通过USER_SOURCE可查看函数代码
    SELECT  text
    FROM  user_source
    WHERE  type  =  'FUNCTION'
    ORDER  BY  line;
    
    • 通过USER_OBJECT可查询名称等信息
    SELECT  object_name
    FROM  user_objects
    WHERE  object_type  =  'FUNCTION';
    

    存储过程和函数的对比

    存储过程 函数
    作为PL/SQL语句执行 作为一个表达式执行
    在头部不能包含RETURN语句 在头部必须包含RETURN语句
    可以通过output参数返回值 必须返回一个single值
    可以有一个不包括值的返回语句 必须至少包含一个RETURN语句

    相关文章

      网友评论

        本文标题:Oracle SQL 学习笔记21 - Procedure 和

        本文链接:https://www.haomeiwen.com/subject/swabxhtx.html