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

    9.1 创建存储过程和函数

    9.1.1 创建存储过程

    创建存储过程,需要使用CREATE PROCEDURE语句。
    CREATE PROCEDURE
    sp_name ( [proc_parameter] )[characteristics ...]
    routine_body

    9.1.2 创建存储函数

    创建存储过程,需要使用CREATE FUNCTION语句。
    CREATE FUNCTION
    func_name ( [func_parameter] )
    RETURNS type [characteristic ...]
    routine_body
    这里有可能会出现这样的报错

    ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variabl
    

    注:
    "delimiter//"语句的作用是将MySQL的结束符设置为//,因为MySQL默认的结束符为分号";",为了避免与存储过程中SQL语句的结束符相冲突,需要使用DELIMITER改变存储过程的结束符,并以"END//"结束存储过程,存储过程定义完毕之后再使用"delimiter ;"恢复默认结束符。delimiter也可指定其他符号作为结束符。
    分割线-------
    这时候执行以下代码即可

    set global log_bin_trust_function_creators = 1;
    

    然后在创建存储函数,如下

    mysql> create function c_sch1()
        -> returns int
        -> return (select count(*) from sch1);
    Query OK, 0 rows affected (0.01 sec)
    

    9.1.3 变量的使用

    1.定义变量
    DECLARE var_name[,varname]… date_type [DEFAULT value];
    2.为变量赋值
    SET var_name = expr [, var_name = expr] ...;


    9.1.4 定义条件和处理程序

    1.定义条件
    使用DECLARE语句
    如定义ERROR 1148(42000)错误,名称为command_not_allowed。可以用两种不同的方法来定义。

    方法一:使用sqlstate_value
    declare command_not_allowed condition for sqlstate "42000"
    //方法二:使用mysql_error_code
    declare  command_not_allowed condition for 1148
    

    2.定义处理程序
    还是使用declare语法
    如:
    定义处理程序的几种方法,代码如下

    //方法一:捕获sqlstate_value
    declare continue handler for sqlstate '42S02' set @info="NO_SUCH_TABLE";
    //方法二:捕获mysql_error_code
    declare continue handler for 1146 set @info="NO_SUCH_TABLE";
    //方法三:先定义条件,然后在调用
    declare no_such_table condition for 1146;
    declare continue handler for sqlstate '42S02' set @info="NO_SUCH_TABLE";
    

    9.1.5 光标的使用

    1.声明光标
    DECLARE关键字来声明光标
    DECLARE cursor_name CURSOR FOR select_statement
    cursor_name声明光标的名字
    select_statement是SELECT语句的内容
    2.打开光标
    OPEN cursor_name
    3.使用光标
    FETCH cursor_name INTO var_name[,var_name]...{参数名称}
    4.关闭光标
    close cursor_name

    9.1.6流程控制的使用

    1.if语句,示例

    判断val值是否为空,如果val值为空,就输出字符串'val is Null';否则输出'val is not NULL';if语句都需要使用end if 来结束。

    if val is null
      then select 'val is null';
      else select 'val is not NULL'
    end if;
    

    2.case语句

    示例:判断val值等于1、等于2,或者两者都不等。

    case val
        when 1 then select 'val is 1';
        when 2 then select 'val is 2';
        else select 'val is not 1 or 2';
    end case;
    

    3.loop语句用来重复执行某些语句,与if和case语句相比,loop只是创建一个循环操作的过程,并不进行条件判断。loop内的语句一直重复执行直到循环被退出,跳出循环过程中使用leave子句。

    示例:
    使用LOOP语句进行循环操作,id值小于等于10之前,将重复执行循环过程。

    declare id int default 0;
    add_loop: LOOP
    SET id=id+1;
      if id >=10 then leave add_loop;
      end if;
    end LOOP add_loop;
    

    4.leave语句

    leave语句用来退出任何被标注的流程控制构造
    示例
    使用leave语句退出循环
    循环count加一直到50退出循环

    add_sum: LOOP
    set @count=@count+1;
    if @count=50 then leave add_num;
    end loop add_num;
    

    5.ITERATE

    ITERATE语句将执行顺序转到语句段开头处
    ITERATE label
    ITERATE只出现在LOOP、REPATH和WHILE语句内。ITERATE的意思为"再次循环",label参数表示循环的标志.ITERATE语句必须跟在循环标志前面。
    ITERATE语句示例:

    create procedure doiterate()
    begin
    declare p1 int default 0;
    myloop: LOOP
      set p1 =p1 + 1;
      if p1 < 10 then ITERATE my_loop;
      elseif p1 > 20 then leave my_loop;
      end if;
      select ' p1 is between 10 and 20';
      end LOOP myloop;
    end
    

    p1的默认值为0,当p1的值小于10时,重复执行p1加1的操作;当p1大于10并且小于20时,打印消息' p1 is between 10 and 20‘;当p1大于20时,退出循环。

    6.REPEAT语句

    示例:id值小于等于10之前,将重复执行循环过程

    reclare id  int default 0;
    repeat 
    set id=id +1;
    until id >= 10
    end repeat;
    

    循环执行id+1操作,当id值小于10时,循环重复执行,大于则退出循环

    7.WHILE语句

    示例:
    i值小于10时,将重复执行循环过程

    declare i int default 0;
    while i < 10 DO
    set i = i +1
    end while;
    

    9.2 调用存储过程和函数

    9.2.1 调用存储过程

    存储过程的调用是通过CALL语句进行调用的。
    CALL sp_name([parameter[,...]])

    9.2.2 调用存储函数

    存储函数的使用方法与MySQL内部函数的使用方法是一样的。

    9.3 查看存储过程和函数

    9.3.1 SHOW STATUS语句查看存储过程和函数的状态

    SHOW STATUS语句可以查看存储过程和函数的状态。
    SHOW {PROCEDURE | FUNCTION} STATUS
    [LIKE 'pattern']

    9.3.2 SHOW CREATE语句查看存储过程和函数的定义

    SHOW CREATE语句查看存储过程和函数的状态。
    SHOW CREATE {PROCEDURE | FUNCTION} sp_name

    9.3.3 从information_schema.Routines表中查看存储过程和函数的信息

    MySQL中存储过程和函数的信息存储在information_schema数据库下的Routines表中。可以通过查询该表的记录来查询存储过程和函数的信息。
    SELECT * FROM information_schema.Routines
    WHERE ROUTINE_NAME=' sp_name ' ;

    9.4 修改存储过程和函数

    使用ALTER语句可以修改存储过程或函数的特性。
    ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]

    9.5 删除存储过程和函数

    删除存储过程和函数,可以使用DROP语句。
    DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name

    9.6 MySQL 8.0的新特性——全局变量的持久化

    在MySQL数据库中,全局变量可以通过SET GLOBAL语句来设置。例如设置服务器语句超时的限制,可以通过设置系统变量max_execution_time来实现:
    SET GLOBAL MAX_EXECUTION_TIME=2000;
    使用SET GLOBAL语句设置的变量值只会临时生效。数据库重启后,服务器又会从MySQL配置文件中读取变量的默认值。
    MySQL 8.0版本新增了SET PERSIST命令。例如设置服务器的最大连接数为1000:
    SET PERSIST max_connections = 1000;

    9.7 综合案例——创建存储过程和函数

    创建存储过程和函数
    通过这一章的学习,应该掌握了如何创建存储过程和存储函数,变量的定义、使用,光标的作用和用途,以及MySQL的控制语句。所有的存储过程和存储函数存储在服务器上,只要调用就可以在服务器上执行。
    创建一个存储函数用来统计sch1中的记录数,函数名为ciunt_sch()
    1.创建函数时报错

    mysql> delimiter //
    mysql> create function count_sch()
        -> returns int
        -> return (select count(*) from sch1);
        -> //
    ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
    

    2.解决方法

    mysql> set global log_bin_trust_function_creators=1
        -> ;
        -> //
    Query OK, 0 rows affected (0.00 sec)
    

    3.重新创建即可

    mysql> create function count_sch()
        -> returns int
        -> return (select count(*) from sch1);
        -> //
    Query OK, 0 rows affected (0.01 sec)
    

    4.调用函数

    mysql> select count_sch() //
    +-------------+
    | count_sch() |
    +-------------+
    |           2 |
    +-------------+
    1 row in set (0.00 sec)
    

    创建一个存储过程,通过调用存储函数的方法获取表sch中的记录数和sch表中id的和。存储过程名称为add_id,同时使用前面创建的存储函数返回表sch中的记录数,计算出表中所有id之和。

    mysql> create procedure add_id1(out count int)
        -> begin
        -> declare itmp int;
        -> declare cur_id cursor for select id from sch1;
        -> declare exit handler for not found close cur_id;
        -> select count_sch() into count;
        -> set @sum=0;
        -> open cur_id;
        -> repeat
        -> fetch cur_id into itmp;
        -> if itmp<10
        -> then set @sum = @sum + itmp;
        -> end if;
        -> until 0 end repeat;
        -> close cur_id;
        -> end;
        -> //
    Query OK, 0 rows affected (0.10 sec)
    

    这个存储过程的代码中使用到了变量的声明、光标、流程控制、在存储过程中调用存储函数等知识点,结果应该是两条记录,id之和为3;
    但这里我调用出来的好像只有存储函数的返回结果,代码如下

    mysql> call add_id1(@sum)
        -> //
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select @sum//
    +------+
    | @sum |
    +------+
    |    2 |
    +------+
    1 row in set (0.00 sec)
    

    常见疑惑及解答

    MySQL存储过程和函数有什么区别?

    在本质上,他们都是存储程序。函数只能通过return语句返回单个值或者表对象;而存储过程不允许执行return,但是可以通过out参数返回多个值。函数限制比较多,不能用临时表,只能用表变量,还有一些函数不可用,等等;而存储过程的限制就比较少。函数可以嵌入在SQL语句中使用,可以在SELECT语句中作为查询语句的一部分调用;而存储过程一般是作为一个独立的部分来执行的。

    存储过程中的代码可以改变么

    目前,MySQL还不提供对已存在的存储过程代码的修改,如果必须要修改存储过程,就必须使用DROP语句删除之后,重新编写代码,或者创建一个新的存储过程。

    存储过程中可以调用其他存储过程么

    存储过程包含用户定义的SQL语句集合,可以使用CALL语句调用其他存储过程,但是不能使用DROP语句删除其他存储过程。

    为什么存储过程的参数不要与数据表中的字段名相同?

    在定义存储过程参数列表时,应注意把参数名与数据库表中的字段名区别开来,否则将出现无法预期的结果。

    存储过程的参数可以使用中文么

    一般情况下,可能会出现存储过程中传入中文参数的情况,例如某个存储过程根据用户的名字查找该用户的信息,传入的参数值可能是中文。这时需要在定义存储过程的时候,在后面加上character set gbk,不然调用存储过程使用中文参数会出错,比如定义userInfo存储过程,代码如下:

    CREATE PROCEDURE userInfo(IN u_name Varchar(50) character set gbk,out u_age INT)
    
    努力拼搏吧,不要害怕,不要去规划,不要迷茫。但你一定要在路上一直的走下去,尽管可能停滞不前,但也要走。
  • 相关阅读:
    【异常】org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter '**' not found.的解决办法
    java如何进行字符串拼接?
    poj2352消防站
    NOIP第7场模拟赛题解
    转载:
    usaco 2010年3月银组题解
    Js 向json对象中添加新元素
    List<T>中 GetRange (int index, int count)的使用
    C# string格式的日期时间字符串转为DateTime类型
    C# DataTable转List<T>--利用反射
  • 原文地址:https://www.cnblogs.com/wkhzwmr/p/15319585.html
Copyright © 2011-2022 走看看