利用mysql存储过程拆分查询出来的字符串的操作
每条数据字符串的结构是:(天天)[100];(新闻)[90];(关键)[100]…这样的结构
期待输出的样子如下:
|
关键字
|
数值
|
|
天天
|
100
|
|
新闻
|
90
|
|
关键
|
100
|
首先拆分一条数据的字符串
把:(天天)[100];(新闻)[90];(关键)[100]
循环拆分成:(天天)[100],在操作拆分成:天天 100
这里我们用到函数
SUBSTRING_INDEX(需要拆分的字符串,以什么符号分割,第几个符号前的字符);
第三个参数为负数时就是取从分割字符起往右侧的字符截取
先定义存储过程变量
DECLARE i INT(11);#循环变量
DECLARE max_size INT(20);#获取有多少分隔符
DECLARE stt VARCHAR(200);#查询每条数据的值
DECLARE num VARCHAR(20);#循环截取用
DECLARE k_var VARCHAR(20);#需要插入的名称
DECLARE k_int VARCHAR(20);#需要插入的值
set stt = select kv from test;
#创建一个临时表,把数据存入,每次执行删除
DROP TABLE IF EXISTS temp_list;#如果存在就删除
CREATE TEMPORARY TABLE temp_list ( #创建临时表
kv VARCHAR(200) NOT NULL,
cou INT NOT NULL
TRUNCATE TABLE temp_list;#清空
SET max_size = LENGTH(stt) - LENGTH(REPLACE(stt, ';', '')) + 1;
#这里用字符串长度-去掉分割字符的长度+1 声明循环的次数
SET i = 1;
WHILE i <= max_size DO循环开始
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(stt, ';', i),';',-1) INTO num;
#字符分割得到(天天)[100]
SELECT SUBSTRING_INDEX(REPLACE(num,'(',''),')',1) into k_var;
#字符分割得到天天
SELECT SUBSTRING_INDEX(REPLACE(num,']',''),'[',-1) into k_int;
#字符分割得到100
INSERT into temp_list VALUES(k_var,k_int);
#把得到的
SET i= i+1;
END WHILE;
select * from temp_list;
END
就能得到想要的了;
但是这只能针对查询出来一条数据的操作
查询出来是多条数据如:
|
kv
|
|
(天天)[100];(新闻)[90];(关键)[100]
|
|
(天天)[100];(新闻)[90];(关键)[100]
|
|
(天天)[100];(新闻)[90];(关键)[100]
|
这样的数据就需要用到游标,循环输出游标,在执行上边的操作。
游标需要
DECLARE done INT DEFAULT 0; # 自定义控制游标循环变量,默认false
#声明游标
#把查询结果赋值给游标tb
DECLARE tb CURSOR FOR SELECT kv FROM test ;
#绑定控制变量到游标,游标循环结束自动转true
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done =1;
#游标循环
OPEN tb;
REPEAT
FETCH tb into stt; #把游标tb的字段赋值给标量stt,多个结果值,需注意顺序
IF NOT DONE THEN
。。。。。这里执行你想要的操作
END IF;
UNTIL done END REPEAT;
CLOSE tb;#关闭游标
我这里还有一个需求那就是需要查询多个表,表中字段一样。
存储过程传入表名,表名为变量
格式为:
table,table1
这时就需要拼接sql
之后用拼接的sql查询把得到的数据赋给游标
但是游标格式
DECLARE tb CURSOR FOR SELECT
无法执行拼接sql
这时需要用到视图功能
把拼接sql执行并放入到视图中
游标在直接查询视图
全部代码如下:
DROP** PROCEDURE IF EXISTS `delete_matches`;
DELIMITER ;;
CREATE DEFINER=`root`@`%` PROCEDURE `test`(IN `table_type` varchar(32))
BEGIN#创建存储过程 传入的表名table_type 格式table,table1
DECLARE i INT(11);#循环变量
DECLARE max_size INT(20);#获取有多少分隔符
DECLARE stt VARCHAR(200);#查询每条数据的值
DECLARE num VARCHAR(20);#循环截取用
DECLARE k_var VARCHAR(20);#需要插入的名称
DECLARE k_int VARCHAR(20);#需要插入的值
DECLARE done INT DEFAULT 0; # 自定义控制游标循环变量,默认false
DECLARE max_size_tab INT;
DECLARE i_tab INT;
DECLARE tab_name VARCHAR(20);#表名称
DECLARE temp_sql VARCHAR(400);#拼接sql
DECLARE head_sql VARCHAR(400);#拼接sql
DECLARE un_sql VARCHAR(50);#拼接sql
DECLARE cr_view VARCHAR(50);#拼接sql
#声明游标
DECLARE tb CURSOR FOR SELECT kv FROM v_view ;
#绑定控制变量到游标,游标循环结束自动转true
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done =1;
SET temp_sql='';#需拼接的语句
SET head_sql='SELECT kv FROM ';#需拼接的语句
SET un_sql = ' UNION ALL ';#需拼接的语句
SET cr_view = 'create view v_view as ';#创建视图语句
#循环输出传入的表名
SET max_size_tab = LENGTH(table_type) - LENGTH(REPLACE(table_type, ',', '')) + 1;
IF max_size_tab>1 THEN
SET i_tab = 1;
WHILE i_tab<=max_size_tab DO
#拆分传入的表名
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(table_type, ',', i_tab),',',-1) INTO tab_name;
IF i_tab=max_size_tab THEN#拼接语句时,最后不需要加union all
SET temp_sql=CONCAT(temp_sql,head_sql,tab_name);#拼接sql语句
ELSE#多张表拼接语句
SET temp_sql=CONCAT(temp_sql,head_sql,tab_name,un_sql);#拼接sql语句
END IF;
SET i_tab = i_tab+1;
END WHILE;
#当传入的表名为一个时,拼接的语句
SET temp_sql=CONCAT(head_sql,table_type);
END IF;
SET temp_sql =CONCAT(cr_view,temp_sql);#拼接创建视图的语句
SET @sql =temp_sql;
#执行拼接sql
PREPARE stmt1 FROM @sql;
EXECUTE stmt1 ;
DEALLOCATE PREPARE stmt1;
#创建临时表
DROP TABLE IF EXISTS temp_list;#如果存在就删除
CREATE TEMPORARY TABLE temp_list ( #创建临时表
kv VARCHAR(200) NOT NULL,
cou INT NOT NULL
TRUNCATE TABLE temp_list;#清空
#游标循环
OPEN tb;
REPEAT
FETCH tb into stt;
IF NOT DONE THEN
#每条数据的操作
#获取最大的循环次数
SET max_size = LENGTH(stt) - LENGTH(REPLACE(stt, ';', '')) + 1;
SET i = 1;
WHILE i <= max_size DO
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(stt, ';', i),';',-1) INTO num;
SELECT SUBSTRING_INDEX(REPLACE(num,'(',''),')',1) into k_var;
SELECT SUBSTRING_INDEX(REPLACE(num,']',''),'[',-1) into k_int;
INSERT into temp_list VALUES(k_var,k_int);
SET i= i+1;
END WHILE;
END IF;
UNTIL done END REPEAT;
CLOSE tb;
SELECT kv,sum(cou) FROM temp_list GROUP BY kv;#分组求和临时表
DROP VIEW IF EXISTS v_view;#删除视图
DELIMITER ;
总结一下:
1、这个存储过程用到了游标,视图,创建临时表还有一些函数。
2、声明游标那两句要放在定义变量下边,要不是真报错啊。
3、这个过程执行效率怎么样,具体没有试过,只是参考。
4、最后对临时表的操作,就像正常的表一下,可以排序,去多少条啊。