资讯专栏INFORMATION COLUMN

MySQL数据库DDL操作之存储过程和函数

venmos / 640人阅读

摘要:上篇文章介绍了数据库操作中的触发器,本章将详细介绍数据库操作中的存储过程和函数,存储过程和函数在某些复杂业务场景下还是有很大作用的。定义和作用存储过程和函数是数据库中预先编译好的一个为了完成特定功能的语句集。

上篇文章介绍了MySQL数据库DDL操作中的触发器,本章将详细介绍MySQL数据库DDL操作中的存储过程和函数,存储过程和函数在某些复杂业务场景下还是有很大作用的。

1、定义和作用:

存储过程和函数是数据库中预先编译好的一个为了完成特定功能的SQL语句集。通过存储过程和函数,可以完成一些具有负责处理逻辑的数据库操作,同时可以减少应用程序和数据库服务器之间的数据传输,提升数据库的数据处理效率。

2、使用存储过程和函数的前提:

(1)创建存储过程和函数时,需要用户具备"CREATE ROUTINE"的权限;
(2)在删除和修改存储过程和函数时,需要用户具备"ALTER ROUTINE"的权限;
(3)在执行存储过程和函数时,需要用户具备"EXECUTE"的权限;

3、储存过程的创建和修改:

(1)存储过程创建的语法:

CREATE PROCEDURE p_name ([procedure_parameter[,...]])
BEGIN
    [characteristic ...]
    ...procedure_statement...  #存储过程的逻辑处理语句
END

参数解释:

procedure_name:存储过程的名称
procedure_parameter:存储过程的参数,可以包含多个参数,procedure_parameter中又包含了存储过程参数
类型、参数名称和参数的具体数据类型,它的定义格式为:[IN|OUT|INOUT] parameter_name field_type
characteristic:表示要修改存储过程的哪个部分,该参数的取值包括以下几种:
    a. CONTAINS SQL,表示子程序包含SQL语句,但是,不包含读或写数据的语句
    b. NO SQL,表示子程序中,不包含SQL语句
    c. READS SQL DATA,表示子程序中,包含读数据的语句
    d. MODIFIES DATA,表示子程序中,包含写数据的语句
    e. SQL SECURITY {DEFINER | INVOKER},指明谁有权限来执行
        DEFINER,表示只有定义者,自己才能够执行
        INVOKER,表示调用者可以执行
    f. COMMENT "conte",表示注释信息
    g. LANGUAGE SQL,表示存储过程使用SQL语句来实现[默认],为后期引入其他语言实现做准备

存储过程参数类型[IN|OUT|INOUT]说明:

IN:表示该参数为输入参数,即:调用存储过程时所要接收的输入参数,为一个具体的值
OUT:表示该参数为输出参数,即:存储过程在被调用时,需要接收的一个外部变量,通常使用@加变量名定义,比如:"@a"。在存储过程处理完结果之后,可以将结果放在该外部变量中,供外部查看;
INOUT:表示该参数即可作为输入参数,接收一个具体的值;同时也可以作为输出参数,通过传入外部变量,完成在存储过程外部查看变量的值;

(2)示例应用:

示例1:创建一个存储过程,查询表出指定表中的记录数,并可以在存储过程外部查看:

修改默认定界符为$,也可使用DELIMITER命令完成

mysql> d $

创建存储过程:

mysql> CREATE PROCEDURE p_count(OUT param INT)
       BEGIN
            SELECT COUNT(*) FROM t_user INTO param FROM t_user;
       END $

将修改的定界符恢复至默认定界符

mysql> d ;

使用CALL命令调用存储过程,传入@a变量,该变量在存储过程中被赋值:

mysql> CALL p_count(@a);

查看通过存储过程所查询到的表中记录数量:
注:查询自定义变量使用"@<变量名>",如果查询系统中的变量,可以使用"@@<变量名>",后期系统参数调优时介绍,此处可以先了解

mysql> SELECT @a;
+--------+
| @a     |
+--------+
|      3 |
+--------+
1 row in set (0.00 sec)

示例2:创建一个存储过程,封装MySQL的LIMIT函数,实现分页:

创建存储过程:

mysql> d $
mysql> CREATE PROCEDURE p_page(IN pageNo INT,IN pageSize INT)
       BEGIN
           SELECT * FROM t_user LIMIT pageNo,pageSize;
       END $
mysql> d ;

调用存储过程,根据具体传入的值查询记录:

mysql> CALL p_page(1,10);

注意:
(1)如果使用的是普通用户登录MySQL来执行存储过程,则需要注意权限问题。如果用户对某个表没有查询权限,则该用户如果调用了某个包含对该表有查询操作的存储过程,会调用失败;
(2)在一个存储过程中可以调用其他的函数或者存储过程,如上示例2,可以调用系统函数LIMIT;
(3)在存储过程中可以完成事务的操作,比如:"提交事务(COMMIT)和回滚事务(ROLLBACK)",但是不能完成"LOAD DATA INFILE"操作;

(3)存储过程的修改:
目前,存储过程暂时不支持直接修改其逻辑语句,只支持修改一些存储过程的特征,也就是对characteristic进行修改。

语法:

ALTER PROCEDURE procedure_name [characteristic ...];

示例:对上述的p_page存储过程进行修改,指明调用者可以执行该存储过程:

mysql> ALTER PROCEDURE p_page SQL SECURITY INVOKER;

4、函数的创建和修改:

(1)函数创建的语法:

CREATE FUNCTION function_name([function_parameter[,...]])
RETURNS type
BEGIN
    [chracteristic ...]
    ...function statement... #函数中的实现逻辑
END

参数解释:

function_name:函数名称
function_parameter:函数的参数,它的定义格式为:"param_name field_type"
[characteristic]:表示要修改的函数的哪个部分,包括的内容和存储过程相同
RETURNS type:表示返回值的声明

(2)示例应用:
示例1:创建一个函数,对于输入的内容,会在内容之前拼接"hello"字符串,在结束位置拼接"!"符号,实现如下:
创建函数:

mysql> CREATE FUNCTION function_hello(str CHAR(20))
        RETURNS CHAR(50) DETERMINISTIC
        RETURN CONCAT("Hello ",str,"!");

调用函数,传入字符串"Tomcat",输出为:"Hello ,Tomcat!",如下:

mysql> SELECT function_hello("Tomcat");
+--------------------------+
| function_hello("Tomcat") |
+--------------------------+
| Hello Tomcat!            |
+--------------------------+
1 row in set (0.00 sec)

说明:
RETURNS CHAR(50):表示返回值类型为CHAR(50)
RETURN CONCAT("Hello ",str,"!"):表示具体的返回值是使用CONCAT函数拼接得到的
DETERMINISTIC:指明存储过程执行的结果是否正确。DETERMINISTIC 表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出。

示例2:实现一个加法功能的函数,输入两个INT类型的值,计算这两个数的和:
定义函数:

mysql> CREATE FUNCTION function_add1(num1 VARCHAR(20),num2 VARCHAR(20))
       RETURNS INT DETERMINISTIC
       RETURN (IF(num1 REGEXP "[0-9]{1,}",num1,0) + IF(num2 REGEXP "[0-9]{1,}",num2,0));
       

调用,传入10和20,计算出这两个数的和为30,如下:

mysql> SELECT function_add(10,20);
+---------------------+
| function_add(10,20) |
+---------------------+
|                  30 |
+---------------------+
1 row in set (0.00 sec)

注意:该函数中对入参做了简单判断,判断是否为数值,如果不为数值,默认当做0处理;

(3)函数的修改:
上面修改存储过程中介绍了使用ALTER完成的方法,此处直接通过修改系统中的mysql表中的数据来修改函数,对应的表为:mysql库中的proc

示例:将function_hello函数的定义者修改为"tomcat"@"localhost"。要修改的用户必须提前存在,修改方式如下:

选库:

mysql> USE mysql;

修改函数的定义者:

mysql> UPDATE proc SET definer = "tomcat@localhost" WHERE name = "function_hello";

刷新权限,如果不执行该操作,修改的结果不会生效:

mysql> FLUSH PRIVILEGES;

5、存储过程和函数的查看和删除:
(1)查看已经创建的存储过程或者函数:
语法:

SHOW  STATUS LIKE "pattern";

参数解释:

pattern:表示存储过程或者函数名称的匹配串,支持模糊匹配

示例1:查看创建的p_page存储过程:

mysql> SHOW PROCEDURE STATUS LIKE "p_page" G
*************************** 1. row ***************************
                  Db: test
                Name: p_page
                Type: PROCEDURE
             Definer: root@127.0.0.1
            Modified: 2018-05-16 11:56:56
             Created: 2018-05-16 11:21:45
       Security_type: INVOKER
             Comment: 
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (0.00 sec)

示例2:查看创建的函数"function_hello":

mysql> SHOW FUNCTION STATUS LIKE "%hello" G
*************************** 1. row ***************************
                  Db: test
                Name: function_hello
                Type: FUNCTION
             Definer: root@127.0.0.1
            Modified: 2018-05-16 12:09:17
             Created: 2018-05-16 12:09:17
       Security_type: DEFINER
             Comment: 
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (0.01 sec)

(2)查看存储过程或者函数的定义:
语法:

SHOW CREATE  ;

示例1:查看触发器p_page的创建过程:
选库:

mysql> USE test;

查看创建过程:

mysql> SHOW CREATE PROCEDURE p_page G
*************************** 1. row ***************************
           Procedure: p_page
            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
    Create Procedure: CREATE DEFINER=`root`@`127.0.0.1` PROCEDURE `p_page`(IN pageNo INT,IN pageSize INT)
    SQL SECURITY INVOKER
begin
select * from t_user limit pageNo,pageSize ;
end
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (0.00 sec)

示例2:查看函数function_hello的创建过程:
选库:

mysql> USE test;

查看创建过程:

mysql> SHOW CREATE FUNCTION function_hello G
*************************** 1. row ***************************
            Function: function_hello
            sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
     Create Function: CREATE DEFINER=`root`@`127.0.0.1` FUNCTION `function_hello`(str CHAR(20)) RETURNS char(50) CHARSET utf8
    DETERMINISTIC
RETURN CONCAT("Hello ",str,"!")
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8_general_ci
1 row in set (0.00 sec)

注意:
查看存储过程和函数的定义还可以通过系统库information_schema中的routines表来查看,主要包括的字段有:ROUTINE_SCHEMA,ROUTINE_NAME,ROUTINE_BODY,ROUTINE_COMMENT,DEFINER

mysql> SELECT ROUTINE_SCHEMA,ROUTINE_NAME,ROUTINE_BODY,ROUTINE_COMMENT,DEFINER FROM information_schema.routines;

解释:

ROUTINE_SCHEMA:存储过程或者函数所在的库
ROUTINE_NAME:存储过程或者函数名称
ROUTINE_BODY:存储过程或者函数体
ROUTINE_COMMENT:注释信息
DEFINER:存储过程或者函数的定义者

6、删除存储过程和函数:
语法:

DROP  ;

示例1:删除存储过程p_page:

mysql> USE test;
mysql> DROP PROCEDURE p_page;

示例2:删除函数function_hello:

mysql> USE test;
mysql> DROP FUNCTION function_hello;

7、变量的定义和赋值:
(1)变量的定义:
语法:

DECLARE var_name type ;

参数解释:

var_name:表示参数名称
type:表示参数类型
var_value:表示参数的默认初始值

示例1:定义一个INT类型的变量SUM,默认值为0:

DECLARE SUM INT DEFAULT 0;

示例2:定义一个VARCHAR(20)类型的变量STR,无初始值:

DECLARE STR VARCHAR(20);

(2)变量的赋值:
语法:
a.直接通过SET赋值:

SET var_name = var_value;

b.通过SELECT查询到结果之后再赋值:

SELECT  INTO var_name ;

示例1:给VARCHAR(20)类型的变量STR赋一个初始值为""

mysql> SET STR = "";

示例2:查询表t_user中的记录数量,并将结果赋值给INT类型的STU_COUNT变量

mysql> SELECT COUNT(*) INTO STU_COUNT FROM t_user;

8、条件定义和处理:
语法:
a.条件的定义:

DECLARE condition_name CONDITION FOR condition_value;
condition_value:
    SQLSTATE sql_state_value

参数解释:

condition_name:表示条件的名称
condition_value:表示条件中所关注的执行结果,通常为SQL的执行状态

b.条件的处理:

DECLARE handler_name HANDLER FOR condition_value do_statement;

参数解释:

handler_name:表示处理器的名称,常用的有:"CONTINUE","SQLWARNING","NOT FOUND","SQLEXCEPTION"
condition_value:表示执行的结果,当处理器匹配到该结果时,会执行后面的do_statement

示例:在一个存储过程中连续给t_user表中插入相同的数据,如果插入失败,则继续向下执行,而不退出

mysql> d $
mysql> CREATE PROCEDURE p_insert()
        BEGIN
            DECLARE CONTINUE HANDLER FOR SQLSTATE "23000" SET @state = 1;
            INSERT INTO t_user(id,name,age) VALUES(1,"bing",23);
            INSERT INTO t_user(id,name,age) VALUES(1,"bing",23);
            SET @val = 666;  
        END $
mysql> d ;
mysql> SELECT @state,@val;
+--------+------+
| @state | @val |
+--------+------+
|      1 |  666 |
+--------+------+
1 row in set (0.00 sec)

结果分析:在上述的存储过程中,第二次插入t_user表中的记录由于主键冲突,故会插入失败。如果不定义条件处理的话。"SET @val=666"不会被执行,最后查出来的@val也不会为666,同样,@state也不会为1,现在查出来的结果分别为1和666,表示处理器起作用了。主键冲突的时候会提示"23000"状态码.

9、游标的使用:
(1)定义:
简单的理解,游标就是一个查询结果集的出口。在这个出口,可以完成对结果的筛选和其他操作。

(2)语法:
a.声明:

DECLARE cursor_name CURSOR FOR select_statement;

b.OPEN:打开游标

OPEN cursor_name;

c.FETCH:将游标的结果保存到某些中间变量中

FETCH cursor_name INTO var_name,...;

d.CLOSE:关闭游标

CLOSE cursor_name;

(3)示例:
使用游标统计出学生表t_student中男生和女生的总人数:
创建测试表结构:

CREATE TABLE t_student(
    id INT PRIMARY KEY AUTO_INCREMENT,
    gender VARCHAR(1) DEFAULT "0" COMMENT "0-男,1-女",
    name VARCHAR(50) DEFAULT ""
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;

测试数据:

INSERT INTO t_student(gender,name) VALUES("1","name01");
INSERT INTO t_student(gender,name) VALUES("0","name03");
INSERT INTO t_student(gender,name) VALUES("0","name06");
INSERT INTO t_student(gender,name) VALUES("0","name08");

创建存储过程:

mysql> d $
mysql> CREATE PROCEDURE student_count()
    BEGIN
        DECLARE str VARCHAR(1);
        DECLARE gender_str CURSOR FOR SELECT gender FROM t_student;
        DECLARE EXIT HANDLER FOR NOT FOUND CLOSE gender_str;
        SET @m_count = 0;
        SET @f_count = 0;
        
        OPEN gender_str;
        REPEAT
            FETCH gender_str INTO str;
            IF str = "1" THEN
                SET @m_count = @m_count + 1;
            ELSE
                SET @f_count = @f_count + 1;
            END IF;
        UNTIL 0 END REPEAT;
        CLOSE gender_str;
    END $

mysql> d ;

调用存储过程:

mysql> CALL student_count();
Query OK, 0 rows affected (0.00 sec)

查看统计结果,M表示女生数量,F表示男生数量,可见,已经使用游标统计完毕:

mysql> SELECT @m_count AS "M",@f_count AS "F" FROM DUAL;
+------+------+
| M    | F    |
+------+------+
|    1 |    3 |
+------+------+
1 row in set (0.00 sec)

10、存储过程和函数中的流程控制,主要介绍一下常用的IF,CASE,LOOP,REPEAT,WHILE流程控制:
(1)IF
语法:

IF search_conditoin THEN statement
    elseif search_condition THEN state
END IF

示例:已经在上述的游标中使用到了,可自行查看。

(2)CASE
语法:

CASE case_value
    WHEN when_value THEN statement
    WHEN when_value THEN statement
    ... #可有多个判断语句
    ELSE statement
END CASE

示例:将上述判断学生性别中使用的IF改为CASE如下:

CASE str
    WHEN "1" THEN
        SET @m_count = @m_count + 1;
    ELSE
        SET @f_count = @m_count + 1;
END CASE;

(3)LOOP
语法:

[loop_label:] LOOP
    statement
END LOOP [loop_label];

示例:
LOOP通常用在循环语句中,处于BEGIN...END之间,如果没有退出语句的话,会一直循环下去,造成死循环,可以和LEAVE一块使用,如下,求1+2+...+100的和:

创建存储过程:

mysql> d $
mysql> CREATE PROCEDURE p_getsum()
BEGIN
    SET @sum = 0;
    SET @i = 0;
    label:LOOP
        SET @i = @i + 1;
        SET @sum = @sum + @i;
        IF @i = 100 THEN
            LEAVE label;
        END IF;
    END LOOP label;
END $
mysql> d ;

调用存储过程并查看结果:

mysql> CALL p_getsum();
mysql> SELECT @sum;
+------+
| @sum |
+------+
| 5050 |
+------+
1 row in set (0.00 sec)

说明:
LEAVE:通常用在循环结构中,用来退出指定标记的循环,如上"LEAVE label",表示跳出名称为label的循环,即:退出LOOP循环。
(4)REPEAT
语法:

[label:]REPEAT
    statement
UNTIL search_condition
END REPEAT [label]

示例:求1+2+...+100的和:
创建存储过程:

mysql> d $
mysql> CREATE PROCEDURE p_getsum1()
BEGIN
    SET @i = 0;
    SET @SUM = 0;
    REPEAT
        SET @i = @i + 1;
        SET @sum = @sum + @i;
    UNTIL @i > 99
    END REPEAT;
    SELECT @sum FROM DUAL;
END $
mysql> d ;

调用存储过程,显示1+2+...+100的值:

mysql> CALL p_getsum1();
+------+
| @sum |
+------+
| 5050 |
+------+
1 row in set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)

(5)WHILE
语法:

[label:]WHILE search_condition DO
    statement
END WHILE [label];

示例:求1+2+...+100的和:
创建存储过程:

mysql> d $
mysql> CREATE PROCEDURE p_getsum()
BEGIN
    SET @i = 0;
    SET @sum = 0;
    WHILE @i < 100 DO
        SET @i = @i + 1;
        SET @sum = @sum + @i;
    END WHILE;
    SELECT @sum FROM DUAL;
END $
d ;

调用存储过程,查看结果:

CALL p_getsum();
+------+
| @sum |
+------+
| 5050 |
+------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)

此处举了一个简单的求和的例子,说明了一下存储过程中的流程控制,负责的流程控制也是由这些简单的组合而成的。简单的掌握了,就可以在这个基础上写出更复杂的存储过程。

11、存储过程的优缺点:
优点:
(1)可以完成实时的复杂报表数据处理及统计;
(2)可以很好的解决某些业务系统和数据库之间的耦合度,比如政府、银行或者金融系统中,一旦存储过程调试完毕,会稳定运行,减少很大一部分不必要的系统间交互;
缺点:
(1)互联网行业大并发场景,存储过程会由于访问量大,而且同时操作多张表,有可能会造成死锁,不好排查,导致数据库出现瓶颈。所以应该慎用,最好别用;
(2)迁移会比较麻烦,如果存储过程中用到了多张表,必须先保证表结构迁移正确,否则存储过程迁移时会出现错误;
(3)如果数据库中的某些表结构变化了,可能需要重新删除并创建存储过程,可扩展性较差;
(4)存储过程多数情况下都是由DBA编写,普通开发人员不容易掌握;

至此,存储过程和函数相关的内容介绍完毕,文中举的示例都是特别简单的,能够说明问题,有错误请大家指出。欢迎评论,转发,一块学习~

后续文章将更新在个人小站上,欢迎查看。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/47785.html

相关文章

  • MySQL基本操作-DDL,DML,DQL,DCL

    摘要:基本操作之数据定义语言,数据操纵语言,数据查询语言,数据控制语言一数据定义语言作用数据定义语言主要用来定义数据库中的各类对象,包括用户库表视图索引触发器事件存储过程和函数等。 MySQL基本操作之DDL(数据定义语言),DML(数据操纵语言),DQL(数据查询语言),DCL(数据控制语言) 一、DDL--数据定义语言作用:数据定义语言主要用来定义数据库中的各类对象,包括用户、库、表、视...

    frank_fun 评论0 收藏0
  • MySQL据库DDL触发器应用

    摘要:至此,触发器相关内容介绍完毕,下一个章节介绍存储过程和函数,欢迎转发,讨论,共同学习 上篇文章简单介绍了一下MySQL的基本操作之DDL、DML、DQL、DCL,在DDL中简单提了一下触发器,存储过程和函数,本篇文章将详细介绍触发器! 1、触发器作用:简单来说,触发器就是绑定在某个表上的一个特定数据库对象,当在这个表上发生某种触发器所监听的操作时,将会触发某种动作。 2、触发器用法: ...

    syoya 评论0 收藏0
  • MySQL据库DDL操作事件调度器

    摘要:中的事件调度器是在版本之后新增的,可以在数据库中定时触发某种操作,类似于中的定时任务或者中的任务调度器,下面将介绍中事件调度器的用法。 MySQL中的事件调度器是在5.1版本之后新增的,可以在数据库中定时触发某种操作,类似于Spring中的Quartz定时任务或者Linux中的crontab任务调度器,下面将介绍MySQL中事件调度器的用法。 1、调度器的创建:(1)语法: CREAT...

    goji 评论0 收藏0
  • 在线ER模型设计:可视化MySQL据库建表及操作

    摘要:让您在线创建流程图系统部署图软件架构图模型组织图软件流程图图表。使用创建数据库模型目前支持及基本的语句建表。后期会进行功能拓展以支持等等数据库模型建模,支持导入生成模型通过语句生成模型模型导出根据模型生成。 概述 ER模型使用可视化了实体存储的信息,以及直观的呈现了实体与实体的关系,在我们实际的应用系统开发过程中新建ER模型可以更好的理解业务模型,为以后的开发维护工作起到归纳总结的作用...

    james 评论0 收藏0
  • 一款在线ER模型设计工具,支持MySQL、SQLServer、Oracle、Postgresql s

    摘要:给大家介绍一款在线模型生成的工具,可以针对多种数据库的文件在线生成模型图表,支持等数据库。 给大家介绍一款在线ER模型生成的工具,可以针对多种数据库的DDL文件在线生成ER模型图表,支持MySQL、SQLServer、Oracle、PostgreSQL等数据库。主要功能如下: 支持表的创建,同时可以根据数据库的类型不同编辑表结构、字段类型、主键、默认值、索引、备注信息等等 支持视图,...

    魏宪会 评论0 收藏0

发表评论

0条评论

venmos

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<