美文网首页
3. SQL编程之MySQL 存储过程

3. SQL编程之MySQL 存储过程

作者: Alvinzane | 来源:发表于2018-12-27 20:11 被阅读0次

    SQL编程之MySQL 存储过程

    上一篇已经介绍了function与procedure的区别,function主要用来实现只读的功能,当需要涉及修改的需求时,procedure就派上用场.同样的先来个简单的例子,目睹为快:

    USE db_dba;
    
    DELIMITER $$
    CREATE PROCEDURE `P_INIT_TB_T1`()
    BEGIN
    
      DROP TABLE IF EXISTS t1;
    
      CREATE TABLE t1(
        c1 int not null,
        c2 int not null,
        c3 int not null,
        c4 int not null,
        PRIMARY KEY(c1),
        KEY c2(c2)
      ) ENGINE=INNODB;
    
      INSERT INTO t1 VALUES
        (0,0,0,0),
        (1,1,1,0),
        (3,3,3,0),
        (4,2,2,0),
        (6,2,5,0),
        (8,6,6,0),
        (10,4,4,0);
    
    END$$
    
    DELIMITER ;
    

    纳尼,怎么这么眼熟! 这个我想不用做过的解释了,这个procedure的功能就是初始化一个和叶老师讲InnoDB锁章节用的测试环境.是不是感觉很方便呢? 接下来再次体验一下:

    # 创建PROCEDURE
    mysql> DELIMITER $$
    mysql> DROP PROCEDURE IF EXISTS `P_INIT_TB_T1` $$
    Query OK, 0 rows affected (0.12 sec)
    
    mysql> CREATE PROCEDURE `P_INIT_TB_T1`()
        -> BEGIN
        ->
        ->   DROP TABLE IF EXISTS t1;
        ->
        ->   CREATE TABLE t1(
        ->     c1 int not null,
        ->     c2 int not null,
        ->     c3 int not null,
        ->     c4 int not null,
        ->     PRIMARY KEY(c1),
        ->     KEY c2(c2)
        ->   ) ENGINE=INNODB;
        ->
        ->   INSERT INTO t1 VALUES
        ->     (0,0,0,0),
        ->     (1,1,1,0),
        ->     (3,3,3,0),
        ->     (4,2,2,0),
        ->     (6,2,5,0),
        ->     (8,6,6,0),
        ->     (10,4,4,0);
        ->
        -> END$$
    Query OK, 0 rows affected (0.00 sec)
    mysql> DELIMITER ;
    

    procedure已经创建好了,它的调用方式和function不同,需要用到call关键字.

    mysql> call p_init_tb_t1();
    Query OK, 7 rows affected (0.52 sec)
    

    当你在测试锁时, 不小心改错数据,想要还原t1表的数据, 仅需再call p_init_tb_t1()一下就OK , SO EASY!

    之前也介绍过SQL编程中一些语法,如变量定义,赋值,条件判断,循环,异常处理在function,procedure及trigger中都是通用的,下面再用procedrue作为例子,进一步了解SQL编程的具体语法:

    DELIMITER $$
    DROP PROCEDURE IF EXISTS `P_INIT_TB_T2` $$
    
    -- 请注意,这次多出了两个参数,用IN和OUT修饰, 分别代表输入参数和输出参数
    -- 参数的命名也分别用"I_"和"O_"进行区分,使其更加清晰
    CREATE PROCEDURE `P_INIT_TB_T2`(IN I_TOTAL INT,OUT O_RESULT TINYINT)
    -- 申明带label的语句块
    main_label:BEGIN
      -- 功能: 创建表T2,并随机生成I_TOTAL条数据,成功返回O_RESULT等于0, 失败返回O_RESULT等于1
    
      -- 定义几个变量,同样都用前缀"C_"来标示,代表CACHE的意思
      DECLARE C_N1 INT DEFAULT 0;
      DECLARE C_NUM INT DEFAULT 0;
      DECLARE C_CHAR VARCHAR(10);
    
      -- 条件判断:超过10000时就退出
      IF I_TOTAL >= 10000 THEN
        SET O_RESULT=1;
        -- 只能使用LEAVE + label的形式来退出指定语名块.本例中是退出整个prcedure
        LEAVE main_label;
      END IF;
      
      -- 标准SQL,删除表
      DROP TABLE IF EXISTS t2;
    
       -- 重新创建
      CREATE TABLE t2(
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `nid` int(11) DEFAULT NULL,
        `cid` varchar(10) DEFAULT NULL,
        `n1` int(11) DEFAULT NULL,
        `c1` varchar(10) DEFAULT NULL,
        PRIMARY KEY (`id`),
        KEY `idx_nid` (`nid`),
        KEY `idx_cid` (`cid`)
      ) ENGINE=INNODB;
    
      -- 循环
      WHILE C_N1 < I_TOTAL DO
        -- 赋值, 不能写成 C_N1++
        SET C_N1 = C_N1 + 1;
    
        -- 随机生成一个数字
        SELECT ROUND(RAND()*1000)
        INTO   C_NUM;
        
        -- 随机生成一串字符
        SELECT REPEAT(CHAR(65 + RAND()*52),10)
        INTO   C_CHAR;
    
        -- 标准的INSERT语句,使用随机生成的值写入T2表
        INSERT INTO t2
        SELECT NULL,C_NUM,C_CHAR,C_NUM,C_CHAR;
    
      END WHILE;
        
        -- 处理返回值,注意: 这里没有return,在procedure中可以实现多个返回值
      SET O_RESULT = 0;
    END$$
    
    DELIMITER ;
    

    为了节约篇幅,我就不再贴创建的过程了.
    由于procedure是用call调用,在获取返回值时需要用到MySQL中的session变量,先普及一下:

    # 创建一个session变量,固定以@开头即可,生命周期是整个session
    mysql> set @a=1;
    Query OK, 0 rows affected (0.00 sec)
    
    # 直接查看值
    mysql> select @a;
    +------+
    | @a   |
    +------+
    |    1 |
    +------+
    1 row in set (0.00 sec)
    
    # 使用session变量进行运算,当然你也可以拿来做where条件
    mysql> select @a + 1;
    +--------+
    | @a + 1 |
    +--------+
    |      2 |
    +--------+
    1 row in set (0.00 sec)
    

    现在来使用session变量来call一下procedure:

    # 调用procedure
    mysql> call p_init_tb_t2(1000000,@result);
    Query OK, 0 rows affected (0.00 sec)
    
    # 查看返回值
    mysql> select @result;
    +---------+
    | @result |
    +---------+
    |       1 |
    +---------+
    1 row in set (0.00 sec)
    
    
    # 调用procedure
    mysql> call p_init_tb_t2(10,@result);
    Query OK, 1 row affected (0.34 sec)
    
    # 查看返回值
    mysql> select @result;
    +---------+
    | @result |
    +---------+
    |       0 |
    +---------+
    1 row in set (0.00 sec)
    
    # 查看t2中的数据
    mysql> select * from t2;
    +----+------+------------+------+------------+
    | id | nid  | cid        | n1   | c1         |
    +----+------+------------+------+------------+
    |  1 |  522 | RRRRRRRRRR |  522 | RRRRRRRRRR |
    |  2 |   69 | TTTTTTTTTT |   69 | TTTTTTTTTT |
    |  3 |  609 | ssssssssss |  609 | ssssssssss |
    |  4 |  949 | oooooooooo |  949 | oooooooooo |
    |  5 |  559 | IIIIIIIIII |  559 | IIIIIIIIII |
    |  6 |   71 | pppppppppp |   71 | pppppppppp |
    |  7 |  325 | pppppppppp |  325 | pppppppppp |
    |  8 |  533 | ssssssssss |  533 | ssssssssss |
    |  9 |  196 | FFFFFFFFFF |  196 | FFFFFFFFFF |
    | 10 |  939 | UUUUUUUUUU |  939 | UUUUUUUUUU |
    +----+------+------------+------+------------+
    10 rows in set (0.00 sec)
    

    可以看出存储过程的SQL编程并不像其它高级语言那么方便, 没有高级的数据结构, 甚至连基础的数组都没有,所以这也是SQL Server和Oracle的同学特别喜欢用临时表的重要原因. 这个例子在处理退出时也用到了类似GOTO的用法,所以要写好SQL程序还是需要多多适应它才行, 实际应用时需要扬长避短.

    procedure的删除,修改,查看和function是一样的,这里不再复述.

    最后总结一下
    看完这篇文章,你至少了解了如下内容:

    • 进一步了解function和procedure的区别
    • session变量的使用
    • 使用条件判断语法
    • 使用循环语法
    • 使用LEAVE退出procedure
    • 学会编写一个利于自己工作procedure

    还有一个异常处理的语法, 将在触发器章节中介绍.

    返回目录

    相关文章

      网友评论

          本文标题:3. SQL编程之MySQL 存储过程

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