zoukankan      html  css  js  c++  java
  • 存储过程

    一、存储过程概述

    存储过程是一个用户定义的函数,由存储过程语句(SPL) 和一组SQL语句组成,以可以执行代码形式存储在数据库中,和表、视图、索引等一样,是数据库的一种对象。

    存储过程语言SPL(Stored Procedure Language),只能用在存储过程中,可以分成下面几类:

    1、变量定义和赋值:define,let

    2、流程控制:

    分支控制:

    if then
    
    elif
    
    else
    
    end if;

    循环控制:

    FOR,FOREACH,WHILE,EXIT, CONTINUE

    3、函数调用与返回

    CALL, SYSTEM ,RETURN

    4、错误处理和调试

    TRACE, ON EXCEPTION, RAISE EXCEPTION

    例子:

    drop procedure count_add;--删除存储过程
    
    create procedure count_add(user_name_var varchar(50) default 'administrator')
    
    --user_name_var传递参数变量在此定义
    
    returning varchar(50);
    
    --返回一个字符型的值
    
    define error_count_var integer;
    
    ----定义输入的次数变量
    
    select error_count into error_count_var from users where user_name=user_name_var;
    
    ----error_count默认是0,从0开始记数
    
    let error_count_var=error_count_var+1;
    
    ----输入一次记数加1
    
    update users set error_count= error_count_var where user_name =user_name_var ;
    
    return user_name_var;
    
    --返回变量值,与returning对应。
    
    return user_name_var WITH RESUME;
    
    ----将保证存储过程继续执行,所有的变量均保持原有的值
    
    end procedure
    
    document ‘this is a error count procedure’
    
    with listing in ’/export/home/xie/errorcount.txt‘;
    
    将该脚本保存为count_add.sql,在unix系统下,执行如下命令建立存储过程:
    
    $dbaccess db1 count_add.sql
    
    存储过程建立在数据库db1中,执行存储过程可以通过dbaccess工具:
    
    $dbaccess db1
    
    然后进入执行状态
    
    execute procedure count_add('administrator');
    
    execute procedure db@servername:count_add('administrator');
    
    与存储过程相关系统表
    
    SYSPROCEDURES:记录数据库的所有存储过程
    
    SYSPROCBODY:记录存储过程文本
    
    SYSPROCPLAN:记录存储过程执行的查询规划
    
    SYSPROCAUTH:记录授予存储过程的权限
    
    查看存储过程代码、导出存储过程
    
    $dbschema -d dbname -f procedurename -ss
    
    例如:
    
    xxxdb% dbschema -d xxdb -f pro1231
    
    DBSCHEMA Schema Utility       INFORMIX-SQL Version 9.40.FC7   
    
    Copyright IBM Corporation 1996, 2004 All rights reserved
    
    Software Serial Number AAA#B000000
    
    create procedure "xxxuser".pro1231()
    
    returning int;
    
    return 2007;
    
    end procedure
    
    document "this is a test"
    
    ;
    
    $dbschema -d dbname -f procedurename proc.sql
    
    从系统表中查看
    
    select data
    
    from sysprocedures, sysprocbody
    
    where datakey ="T"
    
    and sysprocedures.procname = "pro1231"
    
    and sysprocedures.procid =
    
    sysprocbody.procid;
    
    结果显示
    
    data
    
    create procedure pro1231()
    
    returning int;
    
    return 2007;
    
    end procedure
    
    document "this is a test"
    
    ;  

    二、创建存储过程

    语法:

    CREATE [DBA] PROCEDURE 过程名(参数[, 参数 [ ,...]] )
    
                       RETURNING 子句
    
                            语句块
    
                      END   PROCEDURE
    
                      DOCUMENT 子句
    
                      WITH   LISTING   IN 文件名

    过程名说明创建的存储过程的名字

    参数说明调用该存储过程所需的参数个数和类型

    一个存储过程可以不返回任何值,或返回一个或多个值,也可返回多组值。

    返回多组值的存储过程称之为游标式存储过程,对该类存储过程,相应调用函数需作一些特殊处理。

    例子:

    假设建立一个脚本名为proc1231.sql的文件,内容如下:

    create procedure proc1231()
    
    returning int;
    
    return 2007;
    
    end procedure
    
    --end procedure后面不能加分号(;),否则会报语法错误
    
    document
    
    'this is a new procedure'
    
    --这里也不能加分号(;),ducoment子句需加双引号或单引号。
    
    with listing in '/export/home/user/pro.log';
    
    --最后可以加分号(;),也可以不加
    
    存储过程中的语句块由SPL语句和SQL语句组成,但不包含下面的SQL语句
    
    CREATE DATABASE
    
    DATEBASE
    
    CLOSE DATEBASE
    
    CHECK TABLE
    
    REPAIR   INFO   OUTPUT   LOAD   UNLOAD
    
    CREATE PROCEDURE
    
    CREATE PROCEDURE FROM
    
    DOCUMENT子句对存储过程做一些说明,可省略。
    
    WITH LISTING IN 选项说明接受编译器输出信息的文件名,如省略,则编译器不产生输出。
    
    向存储过程中传递变量
    
    create procedure procname(var_num integer default null)
    
    delete from proctable where colno=var_num;
    
    end procedure;
    
    execute procedure procname(11);
    
    return语句
    
    从存储过程中返回0个或多个值
    
    RETURN 语句说明的返回值的个数和类型必须与创建存储过程时说明的返回值的个数和类型一致,或者不返回任何值,在后一情形下,所有的返回值为空值。
    
    WITH RESUME子句将保证存储过程继续执行,所有的变量均保持原有的值。该子句用于返回多组值,比如循环语句中。
    
    create procedure proc_new()
    
    returning int,int;
    
    define num1;
    
    define num2;
    
    .....
    
    ....
    
    return num1,num2;
    
    end procedure;
    
    从SQL中调用存储过程
    
    select * from users
    
    where number=proc_new(23);
    
    call语句
    
    从一个存储过程中调用另一个存储过程
    
    两种格式:
    
    CALL 过程名(参数, ...) RETURNING 变量,...;
    
    CALL 过程名(参数名=参数, ...) RETURNING 变量,...;
    
    说明:
    
    参数可以是SPL表达式或是SELECT语句,只要该语句返回单值,并且具有适当的类型和长度。
    
    如果参数个数多于被调用的存储过程的参数,则返回错误。
    
    如果参数个数少于被调用的存储过程的参数,则未说明的参数被初始化为其缺省值(该值在创建存储过程时说明)若无缺省值,则返回错误。
    
    RETURNING 子句说明的变量用于接收被调用存储过程的返回值,如无返回值,则可省略。
    
    例如:
    
    define var_no1 int;
    
    call proc_new(22) returning var_no1;

    三、存储过程语言

    变量
    
    局部变量
    
    仅在本存储过程中有效的变量。 局部变量不允许有缺省值
    
    全局变量
    
    在同一用户活动期间,存储过程中的可被同一数据库的其它存储过程访问的的变量。全局变量必须在所有使用的存储过程中定义,并且必须给出缺省值,实际的缺省值是第一次被访问时定义的缺省值。
    
    变量(局部变量)的范围
    
    变量在语句块内有效, 如语句块嵌套,则同名的内层定义覆盖其外层定义,内层语句执行完后,外层定义重新有效。
    
    存储过程表达式
    
    存储过程表达式可以是除聚集函数表达式外的任何SQL算术表达式
    
    例子: var_value1; var_value1+var_value2;
    
    变量定义
    
    用DEFINE 语句定义变量,其类型可以是除SERIAL数据类型外 的所有SQL 数据类型
    
    定义TEXT 或BYTE 类型变量时, 需在其变量前加关键字REFERENCES,以表明该变量并不含有真正的数据, 而只是指向数据的指针。
    
    可以使用LIKE定义与字段类型一致的数据类型
    
    传入参数变量的定义在create procedure procname(var_value int)定义
    
    例子:
    
    DEFINE i,j INT;
    
    DEFINE name VARCHAR(12);
    
    DEFINE time_stamp DATETIME YEAR TO SECOND DEFAULT CURRENT YEAR TO SCECOND;
    
    DEFINE date_value DATE;
    
    DEFINE txt REFERENCES TEXT;
    
    DEFINE by REFERENCES BYTE;
    
    DEFINE p_customer like users.customer_num;
    
    定义全局变量
    
    define global global_var int default 0;
    
    局部BLOB数据类型
    
    只使用描述符:
    
    LET
    
    DEFINE
    
    CALL
    
    SELECT
    
    存取BLOB数据:
    
    INSERT
    
    UPDATE
    
    RETURN(到前端应用程序)
    
    变量赋值
    
    四种方式
    
    1、利用LET 语句
    
    LET i, j=1, 0;
    
    LET var_name, var_num=(SELECT username, usernum FROM users WHERE usernum=100);
    
    2、利用SELECT 或SELECT ... INTO 语句
    
    SELECT username INTO var_name FROM users WHERE usernum=100;
    
    3、利用CALL 语句
    
    call proc_new(22) returning var_no1;
    
    4、利用EXECUTE PROCEDURE ...INTO 语句
    
    execute procedure proc_name(username,address into p_name,p_addr);
    
    语句块
    
    create procedure pro_test()
    
    returning int;
    
        begin
    
       
    
        define i int;
    
        let i=1;
    
        end
    
    --begin,end 语句块(显示)
    
    retrun i;
    
    --returning,return语句块(隐含)
    
    end procedure;
    
    foreach循环
    
    create procedure pro_foreach()
    
    define id int;
    
    select userid into id from users where age>30;
    
    --select语句返回大于1的行,可以理解为将select到的值放在id这个列表中一个一个执行。
    
    update others set uservalue=345 where userid=id;
    
    end foreach;
    
    end procedure;
    
    使用update游标
    
    条件分支
    
    if then
    
    elif then
    
    else
    
    end if
    
    --------------------------------------------------
    
    drop procedure pro_dele;
    
    create procedure pro_dele()
    
    define p_time date;
    
    begin work;
    
    foreach curl for
    
    --update游标必须命名
    
    select time_stamp into p_time from pro_dele_tbl
    
    where num > 100
    
    if p_time is not null then
    
    delete from pro_del_tbl where current of curl;
    
    --删除当前记录
    
    end if;
    
    end foreach;
    
    commit work;
    
    --所有修改记录的锁被释放。
    
    end procedure;
    
    --------------------------------------------------
    
    if语句中的表达式
    
    If exists(select username from users
    
       where usernum = 13) then
    
    …
    
    end if
    
    if var_num > all(select usernum from users
    
        where usernum = 23) then
    
    …
    
    end if
    
    if var_name matches “A*” then
    
    …
    
    end if
    
    循环语句while
    
    格式: WHILE 条件语句    语句块   END WHILE
    
    执行过程
    
    先测试条件,若为真,则执行语句块,否则退出循环。
    
    重复上述步骤,开始下一次循环,直到条件为假而退出循环
    
    WHERE 与FOREACH 的区别
    
    WHILE 循环的条件是不定的,循环次数不定,因而可能出现无穷循环
    
    FOR和FOREACH 循环的条件是确定的,循环次数也是明确的,不可能出现无穷循环
    
    例子
    
    create procedure prowhile()
    
    define i int;
    
    define sum int;
    
    let i=1;
    
    let sum=0;
    
    while i<100
    
    let sum=sum+i;
    
    let i=i+1;
    
    end while;
    
    end procedure;
    
    循环语句for
    
    三种格式
    
    FOR 变量 IN (expr1 to expr2 STEP expr3) 语句块   END FOR
    
    --expr1,expr2表示范围,expr3表示步长,默认为1
    
    for i=1 to 10 step 2
    
    ...
    
    end for;
    
    FOR 变量 = (expr1 to expr2 STEP expr3) 语句块   END FOR
    
    --expr1,expr2表示范围,expr3表示步长,默认为1
    
    FOR 变量 IN (expr1, expr2,...) 语句块   END FOR
    
    for i in (1,2,3,4,5,7,8)
    
    ...
    
    end for;
    
    循环的转移
    
    for i = 1 to 10
    
    if i = 5 then
    
    continue for;
    
    ----------------contiune将执行下一次循环
    
    elif i = 8 then
    
    exit for;
    
    ----------------exit for将退出循环,执行for循环的下一条语句
    
    end if;
    
    end for;
    
    循环语句foreach
    
    用 FOREACH 语句可以查询或操作一组记录
    
    FOREACH 隐式定义并打开一个游标
    
    三种格式
    
    FOREACH [WITH HOLD] SELECT ... INTO 语句
    
            语句块
    
    END FOREACH;
    
    -FOREACH 游标名[WITH HOLD] FOR SELECT ... INTO 语句
    
            语句块
    
    END FOREACH;
    
    FOREACH EXECUTE PROCEDURE 存储过程名(参数...参数)
    
         INTO 变量[, 变量[, ...]]    语句块
    
    END FOREACH;
    
    FOREACH 定义的游标在以下情况下关闭:
    
    无行返回
    
    事务提交或回滚导致非保护游标关闭
    
    循环非正常退出(使用EXIT 或 ON EXCEPTION)
    
    操作系统命令
    
    system "echo" "Delete Operation Completed" "|mail judy";
    
    数据库系统一直等到上述命令执行完毕
    
    不能使用返回值判断执行是否成功
    
    如执行不成功,将设置适当的ISAM错误代码和SQL错误代码
    
    检查NOTFOUND条件
    
    create procedure protest()
    
    define num integer;
    
    returning integer;
    
    foreach select usernum into num from users
    
    where usernum=20
    
    --select执行失败将不执行foreach中的语句。
    
    return num;
    
    end foreach;
    
    return;
    
    --return没有返回值将在前端应用中引发NOTFOUND
    
    end procedure;
    
    递归调用
    
    create procedure digui(i int defualt 1)
    
    returning int;
    
    if i <6 then
    
    return 1;
    
    end if;
    
    return n * digui(n-2);
    
    --调用自己
    
    end procedure;
    
    获取serial值
    
    create procedure seri_inst()
    
    define seri int;
    
    insert into users
    
    (user_num,user_date)
    
    values (1,"2006-01-03");
    
    let seri = dbinfo("sqlca.sqlerrd1");
    
    --获取上一条insert语句中的serial值
    
    insert into other(num,name)
    
    values(seri,"new");
    
    end procedure;
    
    获取处理的记录数
    
    create procedure num_rows()
    
    returning int;
    
    define num_rows int;
    
    delete from orders where customer_num = 104;
    
    let num_rows = dbinfo("sqlca.sqlerrd2");
    
    --select、update或update的记录数
    
    return num_rows;
    
    end procedure;
    
    跟踪调试语句trace
    
    存储过程被正确创建后,说明无语法错误,但有可能有逻辑错误
    
    TRACE语句用于调试存储过程, 它可以跟踪以下存储过程实体的值:
    
    变量(Variables)
    
    过程参数(Procedure arguments)
    
    返回值(Return values)
    
    SQL 错误代码(SQL error codes)
    
    ISAM 错误代码(ISAM error codes)
    
    TRACE 语句把跟踪结果写到一个文件中, 该文件由SQL语句SET DEBUG FILE指定
    
    TRACE 语句的三种形式:
    
    TRACE ON :打开跟踪调试, 跟踪所有语句
    
    TRACE OFF :关闭跟踪调试
    
    TRACE PROCEDURE: 对于过程调用,不跟踪过程体,仅跟踪过程的输入和返回值。
    
    create procedure tracepro(var_user_num int)
    
    define var_user_date date;
    
    set debug file to "/export/home/user/trace";
    
    --设置输出文件
    
    trace on;
    
    --跟踪所有执行的语句
    
    select user_date into var_user_date
    
    from users
    
    where user_num = var_user_num;
    
    if var_user_date is null then
    
    trace "user date is null";
    
    --执行到这里输出user date is null
    
    execute procedure other((var_user_num );
    
    end if;
    
    trace off;
    
    --关闭跟踪
    
    end procedure;
    
    存储过程中的异常处理
    
    没有异常处理
    
    create procedure yichang ()
    
    returning int;
    
    define var_num integer;
    
    let var_num = "jack";
    
    --------存储过程到这将会出错
    
            return var_num;
    
    end procedure;
    
    异常处理
    
    create procedure err_deal()
    
    define sql_err int;
    
    define isam_err int;
    
    define error_info char(100);
    
    on exception set sql_err, isam_err, error_info
    
    call error_rout(sql_err,isam_err,error_info);
    
    end exception;
    
    end procedure;
    
    异常捕获:ON EXCEPTION
    
    用ON EXCEPTION语句捕获一个或一组特定的异常(即错误),用错误号标识。
    
    ON EXCEPTION 语句与RAISE EXCEPTION 语句一起提供存储过程语言(SPL)的错误 捕获和恢复机制。
    
    在一个语句块内可以定义多个 ON EXCEPTION 语句。
    
    被捕获的异常可以是系统异常或用户定义的异常。
    
    一旦异常被捕获,错误状态即被清除。
    
    ON EXCEPTION 语句的位置:
    
    ON EXCEPTION 语句是一声明性而非执行性语句,故应位于任何执行语句之前, 而位于DEFINE 语句之后。
    
    格式
    
               ON EXCEPTION IN (错误号,...)
    
               SET SQL 错误变量 ISAM 错误文本变量   语句块
    
               END EXCEPTION [WITH RESUME]
    
    IN 子句说明欲捕获的错误号, 缺省时捕获所有的错误号。
    
    SET 子句接收错误号和错误文本的变量,该语句可省略。
    
    SQL 错误变量: 说明接收SQL 错误号的变量
    
    ISAM错误变量: 说明接收ISAM错误号的变量
    
    错误文本变量:   说明接收与SQL错误号对应的错误文本的变量
    
    WITH RESUME 关键字用于把控制转向到捕获的错误被处理后的紧接发生异常语句后的语句,其效果相当于异常被处理后程序继续执行下去。
    
    WITH RESUME 可以省略。
    
    捕捉特定的错误
    
    create procedure err_deal()
    
    define sql_err int;
    
    define isam_err int;
    
    define error_info char(100);
    
    on exception set sql_err, isam_err, error_info
    
    call error_rout(sql_err,isam_err,error_info);
    
    end exception;
    
    -----其他错误的捕捉
    
            on exception (-206)
    
    call new_tab();
    
    end exception;
    
    -----表不在数据库中的错误在这里捕捉
    
    end procedure;
    
    异常处理后继续执行
    
            on exception (-206)
    
    call new_tab();
    
    end exception with resume;
    
            select new froom tab;
    
    --出错将继续执行
    
            let nex=9;
    
    WITH RESUME将继续
    
    执行出错行后面的语句
    
    如果没有WITH RESUME将继续执行下一次循环或下一个语句块,如果有的话。如果没有语句块,则过程将结束。
    
    异常捕获:RAISE EXCEPTION
    
    用RAISE EXECPTION 语句模拟异常的产生,该异常可被ON EXECTPION语句捕获。
    
    格式:
    
          RAISE EXCEPTION SQL 错误号, ISAM 错误号, 错误文本变量
    
    SQL错误号和ISAM错误号均可是SPL表达式,且其计算结果是一个常数(错误号)
    
    例子:
    
    RAISE EXCEPTION -99999, 0, --Broke the Rule
    
    create procedure err_deal()
    
    define sql_err int;
    
    define isam_err int;
    
    define error_info char(100);
    
    on exception set sql_err, isam_err, error_info
    
    call error_rout(sql_err,isam_err,error_info);
    
                    raise exception sql_err, isam_err, error_info;
    
    ----------------RAISE EXCEPTION引发一个人工的错误信息
    
    end exception;
    
    end procedure;
    
    存储过程的权限
    
    两类存储过程
    
    DBA 权限的存储过程
    
    所有者权限的存储过程
    
    下列用户可以创建存储过程
    
    具有RESOURCE 权限的用户可以创建存储过程
    
    下列用户可以执行存储过程
    
    DBA 用户
    
    存储过程的创建者
    
    具有EXECUTE 权限的用户

    上述内容参考自链接:https://www.cnblogs.com/vmyspace/archive/2012/07/20/2601411.html

    四、实际使用中的注意事项

    4.1

    如果错过太阳时你流了泪,那你也要错过群星了。
    在所有的矛盾中,要优先解决主要矛盾,其他矛盾也就迎刃而解。
    不要做个笨蛋,为失去的郁郁寡欢,聪明的人,已经找到了解决问题的办法,或正在寻找。
  • 相关阅读:
    C++成员变量与函数内存分配
    Sqlite ContentProvider Loader 上下文 对话框
    好书好人生--读书的步骤
    小智慧40
    流媒体开发之-直播界面切换电视台频道
    HDU 4617Weapon(两条异面直线的距离)
    BON取代半岛电视,美国人要“换口味”了吗?
    【Todo】Lucene系统学习
    Zookeeper学习 & Paxos
    C++中的虚继承 & 重载隐藏覆盖的讨论
  • 原文地址:https://www.cnblogs.com/szrs/p/13058948.html
Copyright © 2011-2022 走看看