今天写存储过程时,遇到要将表名最为参数的问题,如果不涉及到游标的话,使用prepare可以解决问题,但是,动态表名要运用在游标中的话,则prepare就得靠边站了。

集众人之智慧,最后,使用临时表解决了问题。

如何在MySQL的存储过程中实现把过程参数用在游标定义的SELECT命令里面作为表名引用

首先,我们来把场景描绘一下,比如下面的例子(当然是无法正确运行的):

  1.  
  2. CREATE PROCEDURE `proc`(SourceDBName CHAR(50), SourceTableName CHAR(50),
  3. TargetDBName CHAR(50), TargetTemplateTableName CHAR(50))
  4. BEGIN
  5. DECLARE done INT DEFAULT 0;
  6. DECLARE FieldValue CHAR(50);
  7. DECLARE CursorSegment CURSOR FOR SELECT ... FROM SourceDBName.SourceTableName;
  8. DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  9.  
  10. OPEN CursorSegment;
  11. REPEAT
  12. FETCH CursorSegment INTO FieldValue;
  13. IF NOT done THEN
  14. ...
  15. END IF;
  16. UNTIL done END REPEAT;
  17. CLOSE CursorSegment;
  18. END$$

上面的例子试图通过存储过程的参数传递,向存储过程内部的游标定义传递要SELECT的数据库名称和表名称。但是,这个存储过程在运行时MySQL会提示“SourceDBName.SourceTableName”不存在。也就是说MySQL不会把SourceDBName和SourceTableName两个标识符作为局部变量去解析,而是直接作为表引用。

要解决这个问题,唯一的方法就是把上面这个存储过程分为3个存储过程。对,3个。所以说这是一个比较复杂的解决办法。

第一个存储过程,扮演的是数据收集器的角色。它接收参数传递过来的数据库名和表名,然后把数据SELECT到一个临时表中。需要注意,临时表的最大好处是它是线程安全的。

第二个存储过程,基于第一个存储过程生成的临时表而创建游标,并处理具体的工作。

第三个存储过程,作为一个入口,负责依次调用存储过程1和存储过程2,并提供相应的参数。

三个存储过程综合起来,就得到下面的例子:

  1.  
  2. CREATE PROCEDURE `proc1`(SourceDBName CHAR(50), SourceTableName CHAR(50))
  3. BEGIN
  4. DECLARE SQLStmt TEXT;
  5.  
  6. SET SQL_NOTES=0;
  7.  
  8. SET @SQLStmt = CONCAT('DROP TEMPORARY TABLE IF EXISTS tmp_table_name');
  9. PREPARE Stmt FROM @SQLStmt;
  10. EXECUTE Stmt;
  11. DEALLOCATE PREPARE Stmt;
  12.  
  13. SET @SQLStmt = CONCAT('CREATE TEMPORARY TABLE tmp_table_name SELECT ... FROM ',
  14. SourceDBName,'.',SourceTableName,' WHERE ... ');
  15. PREPARE Stmt FROM @SQLStmt;
  16. EXECUTE Stmt;
  17. DEALLOCATE PREPARE Stmt;
  18. END$$
  19.  
  20. CREATE PROCEDURE `proc2`(TargetDBName CHAR(50), TargetTemplateTableName CHAR(50))
  21. BEGIN
  22. DECLARE done INT DEFAULT 0;
  23. DECLARE FieldValue CHAR(50);
  24. DECLARE CursorSegment CURSOR FOR SELECT Period FROM tmp_table_name;
  25. DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  26.  
  27. OPEN CursorSegment;
  28. REPEAT
  29. FETCH CursorSegment INTO FieldValue;
  30. IF NOT done THEN
  31. ...
  32. END IF;
  33. UNTIL done END REPEAT;
  34. CLOSE CursorSegment;
  35. END$$
  36.  
  37. CREATE PROCEDURE `proc3`(SourceDBName CHAR(50), SourceTableName CHAR(50),
  38. TargetDBName CHAR(50), TargetTemplateTableName CHAR(50))
  39. BEGIN
  40. CALL proc1(SourceDBName, SourceTableName);
  41. CALL proc2(TargetDBName, TargetTemplateTableName);
  42. END$$
  43.  

补充:运行前需要把系统参数变量“sql_notes”设置为0,否则proc1在DROP TABLE时会停下来。原因是

  1.  
  2. "SQL_NOTES = {0 | 1}
  3. If set to 1 (the default), warnings of Note level are recorded.
  4. If set to 0, Note warnings are suppressed."

mysql 存储过程 动态表名的更多相关文章

  1. mysql的动态表名

    create EVENT createMtpulseTable ON SCHEDULE every 1 month STARTS CURRENT_TIMESTAMP DO CALL pro_creat ...

  2. 关于mysql存储过程创建动态表名及參数处理

      转载请注明出处:帘卷西风的专栏(http://blog.csdn.net/ljxfblog)  近期游戏開始第二次内測,開始处理操作日志.最開始把日志放到同一个表里面,发现一天时间,平均100玩家 ...

  3. MySQL中将数据库表名修改成大写的存储过程

    原文:MySQL中将数据库表名修改成大写的存储过程 MySQL中将数据库表名修改成大写的存储过程 创建存储过程的代码: DROP PROCEDURE IF EXISTS uppercaseTablen ...

  4. Oracle中存储过程传入表名学习

    Oracle中存储过程传入表名: 一.动态清除该表的数据 create or replace procedure p_deletetable(i_tableName in varchar2)  as  ...

  5. hibernate动态表名映射

    引自:http://blog.csdn.net/xvshu/article/details/39187779 最近的一个项目有一个需求,有N个考核单位,要对每个考核单位生成一张考核情况表,这样做的目的 ...

  6. 设置Linux中的Mysql不区分表名大小写

    1. MySQL数据库的表名在Linux系统下是严格区分大小写的,在Windows系统下开发的程序移植到Linux系统下,如果程序中SQL语句没有严格按照大小写访问数据库表,就可能会出现找不到表的错误 ...

  7. MySQL获取Schema表名和字段信息

    MySQL获取Schema表名和字段信息 获取表名 select TABLE_NAME,TABLE_TYPE,ENGINE,TABLE_ROWS,TABLE_COMMENT,CREATE_TIME,U ...

  8. 使用dao时,如何同时使用动态表名和过滤字段?

    使用dao时,如何同时使用动态表名和过滤字段?  发布于 630天前  作者 wukonggg  316 次浏览  复制  上一个帖子  下一个帖子  标签: 无 如题.求样例代码 1 回复 wend ...

  9. MYSQL 存储过程 多表更新异常捕捉和异常处理方式

    今天在做MYSQL 存储过程 多表更新的功能   多表更新时候注意事项 1.首先是确保多表更新能够一次执行,途中没有哪个表的sql语句错误 2.上线后修改表结构及字段,请注意检查是否影响mysql 过 ...

随机推荐

  1. Python基础知识(六)------小数据池,集合,深浅拷贝

    Python基础知识(六)------小数据池,集合,深浅拷贝 一丶小数据池 什么是小数据池: ​ 小数据池就是python中一种提高效率的方式,固定数据类型使用同一个内存地址 代码块 : ​ 一个文 ...

  2. python day 17: UML(统一建模语言)

    python day 17 UML:unified modeling languages,是一种基于面向对象的可视化建模语言. 画图语言:画图要合理.即符合逻辑. 历史: 3.1. 软件功能越来越强大 ...

  3. Git查看某一个文件的历史提交信息

    工作中我们有时候想要查看某一个文件的历史提交版本,] 还想看都修改过那些内容,那么这两个简单的命令就会帮到你了, 话不多说,comeBaby...... 1,首先查看一个文件的历史提交信息 git l ...

  4. FI-FBV0 - No batch input data for screen SAPMF05A 0700

    在预制凭证过账的时候报错:没有屏幕SAPMF05A 0700 的批输入数据 https://answers.sap.com/questions/7203025/fbv0-no-batch-input- ...

  5. MES选型很困惑?避开这三个禁忌!

    MES系统的选型除了要充分剖析自己企业,掌握自己企业的需要.信息化的目标.自身的特点外,还要完全了解MES系统供应商,对其实力.软件性能.服务.用户.软件实施速度.价格进行了解与分析,这也是MES系统 ...

  6. IDEA下创建Spring项目

    IDEA下创建Java SE Spring项目示例 1.创建项目 第4步:是否自动创建空的Spring容器配置文件,默认文件名是spring-config.xml.勾不勾选都行,如果没勾选,后面要自己 ...

  7. .gitignore详解(附上eclipse的java项目的 .gitignore文件)

    今天讲讲Git中非常重要的一个文件――.gitignore. 首先要强调一点,这个文件的完整文件名就是“.gitignore”,注意最前面有个“.”.这样没有扩展名的文件在Windows下不太好创建, ...

  8. 【DATAGUARD】物理dg配置客户端无缝切换 (八.2)--Fast-Start Failover 的配置

    [DATAGUARD]物理dg配置客户端无缝切换 (八.2)--Fast-Start Failover 的配置 一.1  BLOG文档结构图       一.2  前言部分   一.2.1  导读 各 ...

  9. Cglib invoke为什么会死循环?

    目录 Cglib invoke为什么会死循环? 动态代理子类的java文件 动态代理子类实例化过程 动态代理类调用过程 动态代理之MethodProxy.invokeSuper Cglib invok ...

  10. vue---axios实现数据交互与跨域问题

    1. 通过axios实现数据请求 vue.js默认没有提供ajax功能的. 所以使用vue的时候,一般都会使用axios的插件来实现ajax与后端服务器的数据交互. 注意,axios本质上就是java ...