3. SQL编程之MySQL 存储过程

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

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

返回目录

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354