MySQL是一个很强大的关系型数据库,也是目前很常见的数据库之一,各大公司或多或少都会使用到。

最近项目升级,遇到了一点问题。二期测试的时候发现数据库改动有点坑。原来的项目不存在数据库版本管理(而且还是需要部署到甲方的项目(lll¬ω¬)),项目的前辈们都是直接数据库修改,没有留下升级兼容文件之类的东西。导出两个版本的初始数据库设计,使用excel表手动进行字段比较并标注具体改动,编写升级sql等等这些小事就不用多谈了。这次主要是要记录一下 MySQL 的存储过程初体验。因为很少自己编写存储过程,所以这次遇到了一些小问题。

先放上已经编写完成的例子

delimiter //
DROP PROCEDURE  IF EXISTS add_col;
CREATE PROCEDURE add_col (
	IN dname VARCHAR ( 30 ),
	IN tname VARCHAR ( 30 ),
	IN cname VARCHAR ( 30 ),
	IN insql VARCHAR ( 1000 )) 
BEGIN
	set @dname = dname;
	set @tname = tname;
	set @cname = cname;
	IF NOT EXISTS(SELECT column_name FROM information_schema.COLUMNS WHERE table_schema=@dname AND table_name=@tname AND column_name=@cname) THEN
	  set insql = REPLACE(insql,'?1',dname);
	  set insql = REPLACE(insql,'?2',tname);
	  set insql = REPLACE(insql,'?3',cname);
	  set @dsql = insql;
	  select @dsql;
	  PREPARE stmt from @dsql;
	  EXECUTE stmt;
	  DEALLOCATE PREPARE stmt;
	END IF;
END;
//
delimiter ;
-- database name should match the client database name
SET @dname = 'database_name';
SET @tname = 'table_name';
SET @cname = 'col_name';
SET @add_sql = "ALTER TABLE ?1.?2 ADD COLUMN  ?3 varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci default NULL COMMENT 'comments' AFTER  after_col_name;";
CALL add_col ( @dname, @tname, @cname, @add_sql );

DROP PROCEDURE IF EXISTS add_col;

记录一下主要的几个坑点:

  • 自定义在存储过程外的变量需要使用 @变量名 这样的形式来定义,这个貌似是mysql的特性

    set @var_1='变量1' -- 对自定义的变量进行赋值

  • 想必各位应该注意到了delimiter //这个语句(没注意到也没问题,执行的时候找不到问题的语法错误提示会让人欲仙欲死😘)因为MySQL的语句结尾符;默认动作为标识一条语句结束并执行,IF语句的执行可能不完整从而抛出syntax,所以需要使用delimiter来修改执行行为(e.g delimiter //)

  • 预备语句PREPARE stmt from @dsql;为什么要在存储过程内再定义一次呢?因为不定义就会报错当然是为了符合MySQL语句作用域规范了,并且这里的表名不可以使用如EXECUTE stmt USING @var_1,@Var_2;的形式进行动态拼接。本次使用了字符串替换的方法来动态修改表名

嗯,这就是本次存储过程的初体验了,总的来说,除了好些次摸不到头脑的语法报错以外,存储过程还是很好用的👍。当然最重要的是一定要对数据库版本进行管理,严防手工改动数据库,一旦后续版本升级或者数据库变多了以后,没有版本管理,数据库迁移维护和升级会相当吃力。

Q.E.D.


每一个平凡的日常都是连续的奇迹