关于mysql如何创建和使用存储过程,参考笔记《MySQL存储过程和函数创建》以及官网:https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html

本篇主要示例使用了输入参数的存储过程,并解决使用表名作为输入参数的问题,因为之前遇到过需要使用表名作为参数的存储过程,很难处理。

问题描述:

假设我们有TEST1-TEST12共12个相同结构的车辆里程表,我们想要对这12个表进行去重,那么逻辑上比较简单的办法是写12个存储过程处理或者写一个存储过程每执行一次改一次表名并重新编译,但是这样都太麻烦了。

接下来很容易的就会想到是否可以使用表名作为输入参数,这样每次执行给定表名即可。

因此初始的存储过程代码如下:

DELIMITER //
DROP PROCEDURE IF EXISTS Del_Dupilicate;
CREATE DEFINER=`root`@`localhost` PROCEDURE `Del_Dupilicate`(in table_name varchar(64))
BEGIN
DECLARE v_min_id,v_group_count INT;
DECLARE v_get_on_time,v_get_off_time DATETIME;
DECLARE v_car_no VARCHAR(255);
DECLARE done INT DEFAULT FALSE;
DECLARE my_cur CURSOR FOR SELECT get_on_time,get_off_time,car_no,min(id),count(1) AS count FROM table_name GROUP BY get_on_time,get_off_time,car_no HAVING count>1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN my_cur;
myloop: LOOP
FETCH my_cur INTO v_get_on_time,v_get_off_time,v_car_no,v_min_id,v_group_count;
IF done THEN
LEAVE myloop;
END IF;
DELETE FROM table_name WHERE get_on_time=v_get_on_time AND get_off_time=v_get_off_time AND car_no=v_car_no AND id>v_min_id;
COMMIT;
END LOOP;
CLOSE my_cur;
END;
//
DELIMITER ;

上述存储过程可以正常编译,但是执行却一定会报table not exist的错误,因为mysql会错误的把输入变量table_name当做真正的数据库表名,这显然是错误的。

那么如何在SQL中引用变量呢?一个可行的办法是使用动态SQL,把变量拼入SQL语句中然后执行动态SQL。

所以根据官网(https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html)提供的语法,对于上述procedure中的delete语句可以改写成如下格式:

set @del_sql=concat('DELETE FROM ',table_name,' WHERE get_on_time=',v_get_on_time,' AND get_off_time=',v_get_off_time,' AND car_no=',v_car_no,' AND id>',v_min_id)
PREPARE stmt FROM @del_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
//注意prepare目前只能在存储过程中使用,函数和触发器都不适用。

Ps:需要注意的是官网在示例prepare的语法时使用了?作为占位符,但是经试验?不能作为表名的占位符(实际上官网只示例了?可以作为整数字面量的占位符,我猜测凡是数据库对象用?作为占位符都会报错),想要将表名变量整合入SQL中只能使用concat函数,concat的函数的输入支持local variables、user defined variables和input variables。

好,delete语句处理完毕,但是对于cursor中的select语句呢?官网明确说明游标中不能使用动态SQL,也就是不能使用prepare语句,那只能换一种思路了。

游标的作用是什么呢?是获取一个结果集以便进行遍历,那么可否使用临时表代替游标来存储结果集,这样可以使用动态SQL创建临时表(mysql的临时表是session级别的,不同会话可以使用相同名称的临时表,会话释放时临时表自动删除):

set @tmp_table_name=concat(table_name,'_tmp');
set @cur_sql=concat('create temporary table ',@tmp_table_name,' as select get_on_time,get_off_time,car_no,min(id) as min_id,count(1) AS count FROM ',table_name,' GROUP BY get_on_time,get_off_time,car_no HAVING count>1');
PREPARE stmt FROM @cur_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

然后整个存储过程的逻辑就可以更改了,因为我们把中间结果集存入了临时表,那就无需遍历cursor了,同时连declare的local variables也省了(因为这些本地变量是用于遍历游标时存储列值的),只需要delete ... join即可,因此最终的存储过程修改为:

CREATE DEFINER=`root`@`localhost` PROCEDURE `Del_Dupilicate`(in table_name varchar(64))
BEGIN set @tmp_table_name=concat(table_name,'_tmp'); set @cur_sql=concat('create temporary table ',@tmp_table_name,' as select get_on_time,get_off_time,car_no,min(id) as min_id,count(1) AS count FROM ',table_name,' GROUP BY get_on_time,get_off_time,car_no HAVING count>1');
PREPARE stmt FROM @cur_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt; set @del_sql=concat('delete a from ',table_name,' a join ',@tmp_table_name,' b on a.get_on_time=b.get_on_time and a.get_off_time=b.get_off_time and a.car_no=b.car_no and a.id != b.min_id');
PREPARE stmt FROM @del_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt; set @drop_tmp_sql=concat('drop temporary table ',@tmp_table_name);
PREPARE stmt FROM @drop_tmp_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt; END

调用:

call Del_Dupilicate('TEST1');

上述存储过程经过了实测,可以正常的删除重复数据。

使用动态SQL处理table_name作为输入参数的存储过程(MySQL)的更多相关文章

  1. oracle执行带输入输入参数的存储过程

    declare a1 ); a2 ); begin PKG_INPATIENT.prc_autojf('Y', a1, a2); end;

  2. 本地动态SQL

    (转自:http://blog.itpub.net/26622598/viewspace-718134) 一.什么是动态SQL 大多数PL/SQL都做着一件特殊的结果可预知的工作.例如,一个存储过程可 ...

  3. 存储过程中执行动态Sql语句

    MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql;通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有.还有一个最大的好处就 ...

  4. 笔记:MyBatis 动态SQL

    有时候,静态的SQL语句并不能满足应用程序的需求.我们可以根据一些条件,来动态地构建SQL语句.例如,在Web应用程序中,有可能有一些搜索界面,需要输入一个或多个选项,然后根据这些已选择的条件去执行检 ...

  5. T-SQL动态查询(4)——动态SQL

    接上文:T-SQL动态查询(3)--静态SQL 前言: 前面说了很多关于动态查询的内容,本文将介绍使用动态SQL解决动态查询的一些方法. 为什么使用动态SQL: 在很多项目中,动态SQL被广泛使用甚至 ...

  6. 超全MyBatis动态SQL详解!( 看完SQL爽多了)

    MyBatis 令人喜欢的一大特性就是动态 SQL. 在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的. MyBatis 动态 SQL 的出现, 解决了这个麻烦. My ...

  7. SQL Server创建存储过程——动态SQL

    简介: 存储过程(stored procedure)是一组为了完成特定功能的SQL语句集合,经编译后存储在服务器端的数据库中,利用存储过程可以加速SQL语句的执行. 自定义存储过程,由用户创建并能完成 ...

  8. MyBatis动态SQL(认真看看, 以后写SQL就爽多了)

    目录 0 一起来学习 mybatis 1 数据准备 2 if 标签 2.1 在 WHERE 条件中使用 if 标签 2.1.1 查询条件 2.1.2 动态 SQL 2.1.3 测试 2.2 在 UPD ...

  9. 怎样SQL存储过程中执行动态SQL语句

    MSSQL为我们提供了两种动态执行SQL语句的命令,分别是EXEC和sp_executesql;通常,sp_executesql则更具有优势,它提供了输入输出接口,而EXEC没有.还有一个最大的好处就 ...

随机推荐

  1. 第五章 初始jQuery

    jQuery与JavaScript: jQuery的用途: 访问和操作DOM元素: 控制页面样式: 对页面事件的处理: 方便地使用jQuery插件: 与Ajax技术的完美结合: jQuery的优势: ...

  2. ZOJ 2112 Dynamic Rankings(树状数组+主席树)

    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with t ...

  3. Task 的一些个人见解

    Task确实比较好用且优雅 我感觉.NET要成为艺术家... public class TheTask { /// <summary> /// 直接调用是同步方法 /// </sum ...

  4. 大数据学习笔记——HDFS写入过程源码分析(1)

    HDFS写入过程方法调用逻辑 & 源码注释解读 前一篇介绍HDFS模块的博客中,我们重点从实践角度介绍了各种API如何使用以及IDEA的基本安装和配置步骤,而从这一篇开始,将会正式整理HDFS ...

  5. kubernetes-单机实验(入门)

    一.安装kubernetes   实验环境: centos7.0(建议使用7.5版本) 实验机器IP:192.168.1.4 安装方式:yum安装 需求环境:Tomcat+Mysql   1:关闭防火 ...

  6. poj 2513 Colored Sticks (trie树+并查集+欧拉路)

    Colored Sticks Time Limit: 5000MS   Memory Limit: 128000K Total Submissions: 40043   Accepted: 10406 ...

  7. 多线程之美5一 AbstractQueuedSynchronizer源码分析<一>

    AQS的源码分析 目录结构 1.什么是CAS ? 2.同步器类结构 3.CLH同步队列 4.AQS中静态内部类Node 5.方法分析 ​ 5.1.acquire(int arg ) ​ 5.2.rel ...

  8. impala-shell导出数据存在中文异常问题

    由于查询在impala-shell 中没有问题,在导出数据的时候才有问题,这是impala-shell的客户端是由python编写的,而Python无法自动将unicode对象写入没有设置默认编码的输 ...

  9. JS---案例:图标跟着鼠标飞(有bug)

    案例:图标跟着鼠标飞(有bug) <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  10. 去除TextView设置lineSpacingExtra后,最后一行多出的空白

    转载请标明出处:https://www.cnblogs.com/tangZH/p/11985745.html 有些手机中,给TextView设置lineSpacingExtra后会出现最后一行的文字也 ...