美文网首页数据库
15 MySQL 存储过程

15 MySQL 存储过程

作者: Kokoronashi | 来源:发表于2019-02-13 23:08 被阅读17次

    MySQL 存储过程

    [toc]

    存储过程概述

    存储过程介绍

    存储过程,相当于是 MySQL 语句组成的脚本

    • 指的是数据库中保存的一系列 SQL 命令的集合
    • 可以在存储过程中使用变量, 条件判断, 流程控制等

    存储过程优点

    1. 提高性能
    2. 可减轻网络负担
    3. 可以防止对表的直接访问
    4. 避免重复编写 SQL 操作

    基本使用

    创建存储过程

    语法格式

    • delimiter 关键字用来指定 SQL 语句的分隔符 ( 默认为; )
    • 若没有指定分割,编译器会把存储过程当成 SQL 语句进行处理,从而执行出错
    delimiter //
    create procedure 名称()
    begin
        功能代码
        ...
        ...
    end
    //
    delimiter ;
    

    查看存储过程

    方法1

    #查看 use 库中存储过程.
    mysql> show procedure status;
    

    方法2

    #查看某存储过程
    select db,name,type,body from mysql.proc where name="存储过程名";
    

    调用 存储过程

    #不传参时,括号可省略
    call 存储过程名();
    

    删除存储过程

    drop procedure 存储过程名;
    

    示例

    #创建存储过程 say1 
    mysql> delimiter //
    mysql> create procedure say1()
        -> begin
        -> select id,name,shell  from db9.user;
        -> select user,host from mysql.user where user="root";
        -> end
        -> //
    mysql> delimiter ;
    
    #调用存储过程
    mysql> call say1();
    
    #查看所有存储过程,type 是Procedure的是存储过程,Function是函数
    mysql> select db,name,type from mysql.proc;
    +------+-------------------------------------+-----------+
    | db   | name                                | type      |
    +------+-------------------------------------+-----------+
    | db10 | say1                                | PROCEDURE |
    | sys  | extract_schema_from_file_name       | FUNCTION  |
    
    
    #查看某个存储过程
    mysql> select * from mysql.proc where name="say1"\G
    *************************** 1. row ***************************
                      db: db10
                    name: say1
                    type: PROCEDURE
           specific_name: say1
                language: SQL
         sql_data_access: CONTAINS_SQL
        is_deterministic: NO
           security_type: DEFINER
              param_list: 
                 returns: 
                    body: begin
    select id,name,shell  from db9.user;
    select user,host from mysql.user where user="root";
    end
                 definer: root@localhost
                 created: 2019-02-12 22:59:07
                modified: 2019-02-12 22:59:07
                sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
                 comment: 
    character_set_client: utf8
    collation_connection: utf8_general_ci
            db_collation: latin1_swedish_ci
               body_utf8: begin
    select id,name,shell  from db9.user;
    select user,host from mysql.user where user="root";
    end
    
    #查看存储过程 say1 具体功能
    mysql> select body from mysql.proc where name="say1"\G;
    *************************** 1. row ***************************
    body: begin
    select id,name,shell  from db9.user;
    select user,host from mysql.user where user="root";
    end
    
    #删除存储过程
    mysql> drop procedure say1;
    
    #创建存储过程 p1 ,功能显示user表中 shell 是 /bin/bahs的用户个数,调用p1
    mysql> delimiter //
    mysql> create procedure p1()
        -> begin
        -> select count(name) from db9.user where shell="/bin/bash";
        -> end
        -> //
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> delimiter ;
    mysql> call p1();
    +-------------+
    | count(name) |
    +-------------+
    |           1 |
    +-------------+
    1 row in set (0.00 sec)
    
    

    注意

    编写功能体代码时,可以使用变量 条件判断 流程控制 (if 循环) 算数计算 SQL命令

    存储过程进阶

    变量类型

    调用局部变量时,变量名前不需要加@

    名称 说明
    会话变量 会话变量和全局变量叫系统变量 使用 set 命令定义
    全局变量 全局变量的修改会影响到整个服务器,但是对会话变量的修改,只会影响当前的会话
    用户变量 在客户端连接到数据库服务的整个过程中都是有效的.当当前连接断开后所有用户变量失效. 定义 set @变量名=值; 输出 select @变量名;
    局部变量 存储过程中的 begin end,其有效范围仅限于该语句块中,语句块执行完毕后,变量失效. declare专门用来定义局部变量 局部变量 和 参数变量 调用时,变量名前不需要加@

    示例

    #用户变量 自定义变量
    mysql> set @x=20;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select @x;
    +------+
    | @x   |
    +------+
    |   20 |
    
    
    #局部变量 只在存储过程中生效
    mysql> delimiter //
    mysql> create procedure p2()
        -> begin
        -> declare x int default 77;
        -> declare y char(10);
        -> set y="yaya";
        -> select x;
        -> select y;
        -> end
        -> //
    mysql> delimiter ;
    
    #调用存储过程
    mysql> call p2;
    +------+
    | x    |
    +------+
    |   77 |
    +------+
    1 row in set (0.00 sec)
    
    +------+
    | y    |
    +------+
    | yaya |
    +------+
    1 row in set (0.00 sec)
    
    

    查看变量

    #查看全局变量
    mysql> show global variables;
    #查看会话变量
    mysql> show session variables;
    #设置会话变量
    mysql> set seesion sort_buffer_size = 4000;
    #查看会话变量
    mysql> show session variables like "sort_buffer_size";
    +------------------+--------+
    | Variable_name    | Value  |
    +------------------+--------+
    | sort_buffer_size | 262144 |
    +------------------+--------+
    
    #查看全局变量
    mysql> show global variables like "%关键字%";
    
    #用户自定义变量 赋值
    mysql>mysql> set @y=3;
    mysql> select @y;
    +-------+
    | @y    |
    +-------+
    | 3     |
    +-------+
    
    # 使用 SQL 查询结果 赋值
    mysql> select max(uid) into @y from db9.user;
    Query OK, 1 row affected (0.00 sec)
    
    mysql> select @y;
    +-------+
    | @y    |
    +-------+
    | 65534 |
    +-------+
    
    

    参数类型

    语法格式

    1. 调用参数时,名称前不需要加@
    create procedure 名称( 参数1, 参数2 )
    
    1. 参数格式

    参数1= 类型 参数名 数据类型

    create procedure p1( 类型1 参数名1 数据类型1(宽度), 类型2 参数名2 数据类型2(宽度) )
    

    类型

    关键字 名称 描述
    in 输入型参数 (默认类型) 作用是 给存储过程传值,必须在调用存储过程时赋值,在存储过程中该参数的值不允许修改;默认类型是in
    out 输出型参数 该值可在存储过程内部被改变,并可返回.
    inout 输入/输出型参数 调用时指定,并且可被改变和返回

    示例

    >>>>>>>>>>>>>> 输入参数 in 类型
    
    mysql> delimiter //
    #创建 in 类型 输入参数变量 username
    mysql> create procedure p4(in username char(10))
        -> begin
        -> select username;
        -> select name,shell from db9.user where name=username;
        -> end
        -> //
    mysql> delimiter ;
    
    #调用存储过程时赋值
    mysql> call p4("mysql");
    +----------+
    | username |
    +----------+
    | mysql    |
    +----------+
    1 row in set (0.00 sec)
    
    +-------+------------+
    | name  | shell      |
    +-------+------------+
    | mysql | /bin/false |
    +-------+------------+
    1 row in set (0.00 sec)
    
    #创建p5存储过程,可以接受用户输入shell的名字,统计user表中用户输入shell名字的个数.
    mysql> delimiter //
    mysql> create procedure p5(in shellname char(20))
        -> begin
        -> select count(name),shell from db9.user where shell=shellname;
        -> end
        -> //
    mysql> delimiter ;
    
    mysql> call p5("/sbin/nologin");
    +-------------+---------------+
    | count(name) | shell         |
    +-------------+---------------+
    |          18 | /sbin/nologin |
    +-------------+---------------+
    
    
    
    >>>>>>>>>>>>>> 输出参数 out 类型
    
    mysql> set @x=1;
    mysql> drop procedure if exists p2;
    mysql> delimiter //
    # 创建 out 类型 输出参数变量 num
    mysql> create procedure p2(out num int(2))
        -> begin
        # 查看初始值
        -> select num;
        # 改变 num 初始值
        -> set num=7;
        -> select num;
        # SQL查询 赋值给 num
        -> select count(name) into num from db9.user where shell != "/bin/bash";
        -> select num;
        -> end
        -> //
    mysql> delimiter ;
    
    # 调用报错 "错误的参数个数" 无论输入参数输出参数调用时都必须给出.
    mysql> call p2();
    ERROR 1318 (42000): Incorrect number of arguments for PROCEDURE db9.p2; expected 1, got 0
    
    # 调用报错 "输出参数或输入输出参数不是变量" 只有输入参数可以传入常量,输出或输入输出参数都必须是变量.
    mysql> call p2(22);
    ERROR 1414 (42000): OUT or INOUT argument 1 for routine db9.p2 is not a variable or NEW pseudo-variable in BEFORE trigger
    
    # 默认未将 @x 的值赋给 输出参数 变量num,只是占位所以为空. 
    mysql> set @x=1;
    mysql> call p2(@x);
    +------+
    | num  |
    +------+
    | NULL |
    +------+
    1 row in set (0.00 sec)
    
    +------+
    | num  |
    +------+
    |    7 |
    +------+
    1 row in set (0.00 sec)
    
    +------+
    | num  |
    +------+
    |   22 |
    +------+
    1 row in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    # 输出参数 最后会讲存储过程中的值 赋给 @x变量
    mysql> select @x;
    +------+
    | @x   |
    +------+
    |   22 |
    +------+
    
    
    
    >>>>>>>>>>>>>> 输入输出参数 intou类型
    
    mysql> drop procedure if exists p3;
    mysql> delimiter //
    #创建p3 定义输入输出参数类型 num 变量
    mysql> create procedure p3(inout num int(2))
        -> begin
        -> select num;
        -> set num=7;
        -> select num;
        -> select count(name) into num from db9.user where shell != "/bin/bash";
        -> select num;
        -> end
        -> //
    
    mysql> delimiter ;
    mysql> set @x=1;
    #调用p3 传入 @x 值, @x值传给 num变量
    mysql> call p3(@x);
    +------+
    | num  |
    +------+
    |    1 |
    +------+
    1 row in set (0.00 sec)
    
    +------+
    | num  |
    +------+
    |    7 |
    +------+
    1 row in set (0.00 sec)
    
    +------+
    | num  |
    +------+
    |   22 |
    +------+
    1 row in set (0.00 sec)
    
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select @x;
    +------+
    | @x   |
    +------+
    |   22 |
    +------+
    1 row in set (0.00 sec)
    
    

    算术运算

    运算符号

    符号 描述 示例
    + 加法运算 SET @var1=2+2; 4
    - 减法运算 SET @var2=3-2; 1
    * 惩罚运算 SET @var3=3*2; 6
    / 除法运算 SET @var4=10/3; 3.333333333
    DIV 整出运算 SET @var5=10 DIV 3; 3
    % 取模 SET @var6=10%3; 1

    示例

    #加法
    mysql> SET @var1=2+2; 
    mysql> select @var1;
    +-------+
    | @var1 |
    +-------+
    |     4 |
    +-------+
    
    #乘法
    mysql> set @i=2;
    mysql> set @j=3;
    mysql> set @z=@i*@j;
    mysql> select @z;
    +------+
    | @z   |
    +------+
    |    6 |
    +------+
    
    # 创建存储过程p6 计算 /bin/bash 和 /sbin/nologin 用户共有多少
    mysql> delimiter //
    mysql> create procedure p6()
        -> begin
        -> declare x int;
        -> declare y int;
        -> declare z int;
        -> select count(shell) into x from db9.user where shell="/bin/bash";
        -> select count(shell) into y from db9.user where shell="/sbin/nologin";
        -> set z=x+y;
        -> select z;
        -> end
        -> //
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> delimiter ;
    mysql> call p6;
    +------+
    | z    |
    +------+
    |   19 |
    +------+
    
    #创建存储过程p1 计算 传入参数 var1 和 var2 shell的 用户共有多少
    mysql> drop procedure if exists p1;
    mysql> delimiter //
    mysql> create procedure p1(
    in var1 char(20), in var2 char(25),out x int,out y int)
        -> begin
        -> declare z int;
        -> set z=0;
        -> select count(name) into x from db9.user where shell=var1;
        -> select count(name) into y from db9.user where shell=var2;
        -> set z=x+y;
        -> select z;
        -> end
        -> //
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> delimiter ;
    #没有输出参数报错
    mysql> call p1;
    ERROR 1318 (42000): Incorrect number of arguments for PROCEDURE db9.p1; expected 4, got 0
    
    mysql> call p1("/bin/bash","/sbin/nologin",@x,@y);
    +------+
    | z    |
    +------+
    |   19 |
    +------+
    
    

    流程控制

    条件测试

    数值比较
    类型 说明
    = 等于
    > >= 大于 大于或等于
    < <= 小于 小于或等于
    != 不等于
    BETWEEN ... AND .. 在 .. 与 .. 之间
    示例
    
    
    逻辑比较
    类型 用途
    OR AND ! 逻辑或 逻辑与 逻辑非
    IN ... NOT IN ... 在 .. 范围内 不在 .. 范围内
    IS NULL 字段的值为空
    IS NOT NULL 字段的值不为空
    LIKE 模糊匹配
    REGEXP 正则匹配
    示例
    
    

    选择结构

    语法
    # 格式1 if
    if 条件测试 then
        代码 .. ..
        .. ..
    end if;
    
    #格式2 if else
    if 条件测试 then
        代码1 .. ..
        .. ..
    else
        代码2 .. ..
        .. ..
    end if;
    
    示例
    mysql> drop procedure if exists p4;
    mysql> delimiter //
    mysql> create procedure p4( in num int(2))
        -> begin
        ->     if num  <= 10 then
        ->         select id,name,shell from db9.user where id <=num;
        ->     end if;
        -> end
        -> //
    mysql> delimiter ;
    
    mysql> call p4(3);
    +----+--------+---------------+
    | id | name   | shell         |
    +----+--------+---------------+
    |  1 | tom    | /bin/bash     |
    |  2 | bin    | /sbin/nologin |
    |  3 | daemon | /sbin/nologin |
    +----+--------+---------------+
    
    mysql> call p4(11);
    Query OK, 0 rows affected (0.00 sec)
    
    
    #if else end if
    mysql> drop procedure if exists p5;
    mysql> create procedure p5( in num int(2))
        -> begin
        ->     if num  is null then
        ->         select id,name,shell from db9.user where id =2;
        ->     else
        ->         select id,name,shell from db9.user where id<=num;
        ->     end if;
        -> end
        -> //
    mysql> delimiter ;
    
    mysql> set @x=null;
    mysql> call p5(@x);
    +----+------+---------------+
    | id | name | shell         |
    +----+------+---------------+
    |  2 | bin  | /sbin/nologin |
    +----+------+---------------+
    
    mysql> call p5(2);
    +----+------+---------------+
    | id | name | shell         |
    +----+------+---------------+
    |  1 | tom  | /bin/bash     |
    |  2 | bin  | /sbin/nologin |
    +----+------+---------------+
    

    循环结构

    while 条件式循环

    反复测试条件,只要成立就执行命令序列

    while 条件判断 do
        循环体
        .. ..
    end while;
    
    示例
    # 输出1-5
    mysql> delimiter //
    mysql> create procedure p10()
        -> begin 
        -> declare i int(2);
        -> set i=1;
        -> while i<=5 do
        -> select i;
        -> set i=i+1;
        -> end while;
        -> end
        -> //
    mysql> delimiter ;
    mysql> call p10();
    +------+
    | i    |
    +------+
    |    1 |
    +------+
    
    +------+
    | i    |
    +------+
    |    2 |
    +------+
    
    +------+
    | i    |
    +------+
    |    3 |
    +------+
    
    +------+
    | i    |
    +------+
    |    4 |
    +------+
    
    +------+
    | i    |
    +------+
    |    5 |
    +------+
    
    
    #输出 uid 为偶数 的 id,name,uid 
    mysql> drop procedure if exists p6;
    mysql> delimiter //
    mysql> create procedure p6()
        -> begin
        -> declare i int(2);
        -> declare j int(2);
        -> declare z int(2);
        #查看表总行数 行数 存入 i
        -> select count(id) into i from db9.user; 
        -> 
        # id 从1开始 放入变量j 每次自加1
        -> set j=1;
        -> while j<=i do
        ->     select uid into z from db9.user where id=j;
        ->     if z%2=0 then
        ->         select id,name,uid from db9.user where id=j;
        -> end if;
        -> set j=j+1;
        -> end while;
        -> end
        -> //
    mysql> delimiter ;
    
    mysql> call p6();
    +----+------+------+
    | id | name | uid  |
    +----+------+------+
    |  1 | tom  |    0 |
    +----+------+------+
    1 row in set (0.00 sec)
    
    +----+--------+------+
    | id | name   | uid  |
    +----+--------+------+
    |  3 | daemon |    2 |
    +----+--------+------+
    1 row in set (0.00 sec)
    
    +----+------+------+
    | id | name | uid  |
    +----+------+------+
    |  5 | lp   |    4 |
    +----+------+------+
    1 row in set (0.00 sec)
    
    +----+----------+------+
    | id | name     | uid  |
    +----+----------+------+
    |  7 | shutdown |    6 |
    +----+----------+------+
    1 row in set (0.00 sec)
    
    +----+------+------+
    | id | name | uid  |
    +----+------+------+
    |  9 | mail |    8 |
    +----+------+------+
    1 row in set (0.00 sec)
    
    +----+-------+------+
    | id | name  | uid  |
    +----+-------+------+
    | 11 | games |   12 |
    +----+-------+------+
    1 row in set (0.00 sec)
    
    +----+------+------+
    | id | name | uid  |
    +----+------+------+
    | 12 | ftp  |   14 |
    +----+------+------+
    1 row in set (0.00 sec)
    
    +----+-----------------+------+
    | id | name            | uid  |
    +----+-----------------+------+
    | 14 | systemd-network |  192 |
    +----+-----------------+------+
    1 row in set (0.00 sec)
    
    +----+------+------+
    | id | name | uid  |
    +----+------+------+
    | 17 | sshd |   74 |
    +----+------+------+
    1 row in set (0.00 sec)
    
    +----+------+------+
    | id | name | uid  |
    +----+------+------+
    | 19 | ntp  |   38 |
    +----+------+------+
    1 row in set (0.00 sec)
    
    +----+------+------+
    | id | name | uid  |
    +----+------+------+
    | 21 | rpc  |   32 |
    +----+------+------+
    1 row in set (0.00 sec)
    
    +----+-----------+-------+
    | id | name      | uid   |
    +----+-----------+-------+
    | 23 | nfsnobody | 65534 |
    +----+-----------+-------+
    
    
    loop 死循环
    loop
        循环体
        .. ..
    end loop;
    
    示例
    #死循环 不按 ctrl + c 会一直执行.
    drop procedure if exists p7;
    delimiter //
    create procedure p7()
    begin
        declare i int(2);
        set i=1;
        loop
            select i;
            set i=i+1;
        end loop;
    end
    //
    delimiter ;
    
    call p7();
    
    repeat 条件式循环

    条件不成立时,执行循环,符合条件时,结束循环

    repeat
        循环体
        .. ..
        #untill 后面不需要使用;
        until 条件判断
    end repeat;
    
    示例
    mysql> drop procedure if exists p8;
    mysql> delimiter //
    mysql> create procedure p8()
        -> begin
        -> declare i int(2);
        -> set i=1;
        -> repeat
        -> select i;
        -> set i=i+1;
        -> until i=3
        -> end repeat;
        -> end
        -> //
    
    mysql> delimiter ;
    mysql> call p8();
    +------+
    | i    |
    +------+
    |    1 |
    +------+
    1 row in set (0.00 sec)
    
    +------+
    | i    |
    +------+
    |    2 |
    +------+
    1 row in set (0.00 sec)
    
    
    控制循环
    选项 说明 shell相似
    LEAVE 标签名 结束循环的执行 break
    ITERATE 标签名 结束当前循环,并执行下一次循环 continue
    示例
    drop procedure if exists p9;
    delimiter //
    create procedure p9()
    begin
        declare i int(2);
        set i=0;
        # 为循环设置 lab1 标签名
        lab1:loop
            set i=i+1;
            if i=3 then
            #跳出本次循环,继续下一次循环
            ITERATE lab1;
            end if;
             if i=5 then 
             #结束循环执行
            LEAVE lab1;
            end if; 
            select i;       
        end loop;
    end
    //
    delimiter ;
    

    相关文章

      网友评论

        本文标题:15 MySQL 存储过程

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