mysql存储过程
mysql存储过程
1.变量
-
局部变量
-
用户自定义,在begin/end块中有效
-
语法:
declare name type [default var_value]; e.g.: declare name varchar(32);
-
举例:
delimiter $$ CREATE PROCEDURE test1() BEGIN declare nickname varchar(32) default "James"; set nickname = "ming"; select nickname; END$$ call test1()
-
全局变量
-
用户自定义,当前会话(连接)有效
-
语法:
@name -- 不需要提前声明,使用即声明
-
示例:
delimiter $$ CREATE PROCEDURE test2() BEGIN set @nickname = "Lucy"; END$$ call test2 $$ select @nickname $$
-
给全局变量赋值
delimiter $$ CREATE PROCEDURE test3() BEGIN select account.`name` into @username from account where account.id=1; END$$ call test3 $$ select @username $$
-
-
会话变量
-
2.入参与出参
-
语法:
in | out | inout | param_name type
- 入参示例:
delimiter $$ CREATE PROCEDURE test4(in nickname varchar(32)) BEGIN set @user_name = nickname; END$$ call test4("ming") $$ select @user_name $$
- 出参示例:
delimiter $$ CREATE PROCEDURE test5(in address varchar(32), out account_name varchar(32)) BEGIN select account.`name` into account_name from account where account.`address`=address; END$$ call test5("beijing",@account_name) $$ select @account_name $$
- 出入参示例:
delimiter $$ CREATE PROCEDURE test_inout(in address varchar(32), inout account_name varchar(32)) BEGIN declare a_name varchar(32); set a_name = account_name; select account.`name` into account_name from account where account.`address`=address; select concat(a_name, " ",account_name); END$$ -- 执行 set @account_name = "hello"; call test_inout("beijing",@account_name);
3.流程控制
-
IF语法
IF search_condition THEN statement_list [ELSEIF search_condition THEN statement_list]... [ELSE statement_list] END IF
- 示例
delimiter $$ CREATE PROCEDURE test_years(in account_id int) BEGIN declare result varchar(32); declare years int; select timestampdiff(year,account.info_date,now()) into years from account where account.id=account_id; if years > 30 then set result = "老员工"; elseif years > 20 then set result = "骨干"; else set result = "新人"; end if; select result; END$$ -- 执行 call test_years(1);
-
CASE语法
-- 语法1 CASE case_value WHEN when_value THEN statement_list [WHEN when_value THEN statement_list] [ELSE statement_list] END CASE -- 语法2 CASE WHEN search_condition THEN statement_list [WHEN search_condition THEN statement_list]... [ELSE statement_lsit] END CASE
- 示例
delimiter $$ CREATE PROCEDURE test_years_case(in account_id int) BEGIN declare result varchar(32); declare years int; select timestampdiff(year,account.info_date,now()) into years from account where account.id=account_id; case when years > 30 then set result = "老员工"; when years > 20 then set result = "骨干"; else set result = "新人"; end case; select result; END$$ -- 执行 call test_years_case(1);
4.循环
4.1 loop
-
语法
[begin_label:]LOOP statement_list END LOOP [end_label]
-
loop是死循环,需要手动退出循环,我们可以使用leave退出,可以把leave看成break语句,与之对应的,就有iterate(继续循环),类比continue。
- leave示例
delimiter $$ CREATE PROCEDURE test_loop() BEGIN declare c_idx int default 1; tag:loop -- 声明一个loop标签 select c_idx; if c_idx >= 10 then leave tag; -- 条件成立结束死循环 end if; set c_idx = c_idx + 1; end loop tag; END$$ call test_loop()
- iterate + leave 控制循环
delimiter $$ CREATE PROCEDURE test_loop2() BEGIN declare c_idx int default 1; declare result varchar(256) default "1"; tag:loop set c_idx = c_idx +1; set result = concat(result, ',', c_idx); if c_idx < 10 then iterate tag; -- iterate 相当于 python中continue,下面代码不执行 end if; leave tag; -- 当不满足条件时,离开循环 end loop tag; select result; END$$ test_loop2() -- 1,2,3,4,5,6,7,8,9,10
4.2 repeat
-
语法:
[begin_label:] REPEAT statement_list UNTIL search_condition -- 直到...为止 退出循环 END REPEAT [end_label]
-
示例
delimiter $$ CREATE PROCEDURE test_repeat() BEGIN declare c_idx int default 1; declare result varchar(256) default "1"; cnt:repeat set c_idx = c_idx +1; set result = concat(result, ',', c_idx); until c_idx >= 10 end repeat cnt; select result; END$$ -- 执行 call test_repeat()
4.3 while
-
语法
[begin_label:] WHILE search_condition DO statement_list END WHILE [end_label]
- 示例
delimiter $$ CREATE PROCEDURE test_while() BEGIN declare c_idx int default 1; declare result varchar(256) default "1"; while c_idx < 10 Do set c_idx = c_idx +1; set result = concat(result, ",", c_idx); end while; select result; END$$ -- 执行 call test_while() -- 1,2,3,4,5,6,7,8,9,10
5.游标
-
用游标得到某一个结果集,逐行处理数据
-- 声明语法 DECLARE cursor_name CURSOR FOR select_statement; -- 打开语法 OPEN cursor_name -- 取值语法 每次取一行 FETCH cursor_name INTO var_name [, var_name] ... -- 关闭语法 CLOSE cursor_name
- 示例:根据输入地址,打印消息
delimiter $$ CREATE PROCEDURE test_cursor(in address varchar(32)) BEGIN declare uid int; declare uname varchar(32); declare age int; declare lp_flag boolean default true;-- 标记 declare address_cursor cursor for select account.`id`,account.`name`,account.`age` from account where account.`address` = address; -- handler 句柄 当出现 1329异常 将lp_flag改为false 并继续执行, 当把continue换成exit则会 -- 也可以使用NOT FOUND declare continue handler for 1329 set lp_flag = false; open address_cursor;-- 打开游标 -- 遍历游标 cnt:loop fetch address_cursor into uid,uname,age;-- 获取每行数据,当数据没了会报错,这样会触发 handler句柄, if lp_flag then select uid,uname,age; else leave cnt; end if; end loop cnt; close address_cursor;-- 关闭游标 END$$ call test_cursor('beijing');
- 示例:查询beijing,用户名不为ming的岁数加1
delimiter $$ CREATE PROCEDURE test_cursor2(in address varchar(32)) BEGIN declare uid int; declare uname varchar(32); declare age int; declare lp_flag boolean default true;-- 标记 declare address_cursor cursor for select account.`id`,account.`name`,account.`age` from account where account.`address` = address; -- handler 句柄 当出现 1329异常 将lp_flag改为false 并继续执行, 当把continue换成exit则会 -- 也可以使用NOT FOUND declare continue handler for NOT FOUND set lp_flag = false; open address_cursor;-- 打开游标 -- 遍历游标 cnt:loop fetch address_cursor into uid,uname,age;-- 获取每行数据,当数据没了会报错,这样会触发 handler句柄, if lp_flag then if uname = "ming" then iterate cnt; else update account set account.age=account.age + 1 where account.id=uid; end if; else leave cnt; end if; end loop cnt; close address_cursor;-- 关闭游标 END$$ -- 执行 call test_cursor2('beijing');
6.循环创建表
-
我们需要用某个表记录很多数据,比如记录用户行为,当每天记录较多时,如果把所有数据都记录到一张表中,过于庞大,需要分表,我们的要求是每天一张表,存当前统计数据,就要提前创建这些表,每月月底创建下一个月每天的表。
-
知识点:预编译
PREPARE stmt_name FROM preparable_stmt EXECUTE stmt_name [USING @var_name [, @var_name] ...] {DEALLOCATE | DROP} PREPARE stmt_name
-
时间的处理
EXTRACT(unit FROM date) 截取时间的指定位置值 DATE_ADD(date,INTERVAL expr unit) 日期运算 LAST_DAY(date) 获取日期的最后一天 YEAR(date) 返回日期中的年 MONTH(date) 返回日期中的月 DAYOFMONTH(date) 返回日
-
示例代码:
delimiter $$ create procedure sp_create_table() BEGIN declare next_year int; declare next_month int; declare next_month_str char(2); declare next_month_day int; declare next_month_day_str char(2); declare table_name_str char(10); declare t_index int default 1;-- 控制循环 -- 获取下个月年份 set next_year = year(date_add(now(),INTERVAL 1 month)); -- 获取下个月是几月 set next_month = month(date_add(now(), INTERVAL 1 month)); -- 下个月最后一天是几号 set next_month_day = dayofmonth(LAST_DAY(date_add(now(), INTERVAL 1 month))); if next_month < 10 then set next_month_str = concat('0', next_month); else set next_month_str = concat('', next_month); end if; while t_index <= next_month_day do if (t_index < 10) then set next_month_day_str = concat('0', t_index); else set next_month_day_str = concat('',t_index); end if; -- 表名 set table_name_str = concat(next_year, "_", next_month_str, "_", next_month_day_str); -- sql语句拼接 set @create_table_sql = concat( "create table comp_", table_name_str, "(`grade` INT(11) NULL, `losal` INT(11) NULL, `hisal` INT(11) NULL) COLLATE=\'utf8_general_ci\'"); -- 预编译执行语句 FROM后面不能使用局部变量 prepare create_table_stmt FROM @create_table_sql; execute create_table_stmt; DEALLOCATE prepare create_table_stmt; set t_index = t_index + 1; end while; END$$
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库