首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MySQL存储过程:在游标声明中使用变量作为数据库名称

MySQL存储过程:在游标声明中使用变量作为数据库名称
EN

Stack Overflow用户
提问于 2009-11-05 22:17:29
回答 5查看 22.8K关注 0票数 2

我需要在游标的声明中使用一个变量来指示要查询的数据库。以下是代码的一小段:

代码语言:javascript
复制
CREATE PROCEDURE `update_cdrs_lnp_data`(IN dbName VARCHAR(25), OUT returnCode SMALLINT)

cdr_records:BEGIN

DECLARE cdr_record_cursor CURSOR FOR 

 SELECT cdrs_id, called, calling FROM dbName.cdrs WHERE lrn_checked = 'N';

 # Setup logging
 DECLARE EXIT HANDLER FOR SQLEXCEPTION
 BEGIN
      #call log_debug('Got exception in update_cdrs_lnp_data');
      SET returnCode = -1;
 END;

正如您所看到的,我正在尝试使用变量dbName来指示查询应该在哪个数据库中进行。但是,MySQL不会允许这样做。我还尝试了一些东西,比如:

代码语言:javascript
复制
CREATE PROCEDURE `update_cdrs_lnp_data`(IN dbName VARCHAR(25), OUT returnCode SMALLINT)

cdr_records:BEGIN

DECLARE cdr_record_cursor CURSOR FOR 

        SET @query = CONCAT("SELECT cdrs_id, called, calling FROM " ,dbName, ".cdrs WHERE lrn_checked = 'N' ");
        PREPARE STMT FROM @query;
        EXECUTE STMT;

 # Setup logging
 DECLARE EXIT HANDLER FOR SQLEXCEPTION
 BEGIN
      #call log_debug('Got exception in update_cdrs_lnp_data');
      SET returnCode = -1;
 END;

当然,这也不起作用,因为MySQL只允许在游标声明中使用标准的SQL语句。

有没有人能想出一种方法,通过传入应该受到影响的数据库的名称,在多个数据库中使用相同的存储过程?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-04-05 23:16:54

MySQL对Vijay Jadhav的回答是解决这一局限的正确方法。实际上,您需要3个进程才能完成:

proc1使用Vijay Jadhav的方式,其工作方式类似于数据收集器。您需要将变量传递给proc1,并让它为proc2创建临时表。Vijay的方法有一个限制,他应该使用"CREATE TEMPORARY table tmp_table_name SELECT ...“创建一个临时表。因为临时表是线程安全的。

proc2在由proc1创建的临时表上声明游标。由于tmp表是已知的,并且已硬编码到声明中,因此不再出现“未找到表”错误。

proc3的工作方式就像一个“主”函数,所有的参数都需要发送给proc1和proc2。proc3只需先调用proc1,然后使用每个进程所需的参数调用proc2。

p.s需要将系统变量"sql_notes“设置为0,否则proc1会在DROP TABLE命令时停止。

下面是我的例子:

代码语言:javascript
复制
CREATE PROCEDURE `proc1`(SourceDBName CHAR(50), SourceTableName CHAR(50))
BEGIN
  DECLARE SQLStmt TEXT;

  SET @SQLStmt = CONCAT('DROP TEMPORARY TABLE IF EXISTS tmp_table_name');
  PREPARE Stmt FROM @SQLStmt;
  EXECUTE Stmt;
  DEALLOCATE PREPARE Stmt;

  SET @SQLStmt = CONCAT('CREATE TEMPORARY TABLE tmp_table_name SELECT ... FROM ',SourceDBName,'.',SourceTableName,' WHERE ... ');
  PREPARE Stmt FROM @SQLStmt;
  EXECUTE Stmt;
  DEALLOCATE PREPARE Stmt;
END$$

CREATE PROCEDURE `proc2`(TargetDBName CHAR(50), TargetTemplateTableName CHAR(50))
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE FieldValue CHAR(50);
  DECLARE CursorSegment CURSOR FOR SELECT ... FROM tmp_table_name;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  OPEN CursorSegment;
  REPEAT
    FETCH CursorSegment INTO FieldValue;
    IF NOT done THEN
      ...
    END IF;
  UNTIL done END REPEAT;
  CLOSE CursorSegment;
END$$

CREATE PROCEDURE `proc3`(SourceDBName CHAR(50), SourceTableName CHAR(50), TargetDBName CHAR(50), TargetTemplateTableName CHAR(50))
BEGIN
  CALL proc1(SourceDBName, SourceTableName);
  CALL proc2(TargetDBName, TargetTemplateTableName);
END$$
票数 8
EN

Stack Overflow用户

发布于 2009-11-05 23:44:34

不,您不能在游标中这样做。也许准备好的语句就可以完成这项工作?:

代码语言:javascript
复制
delimiter ;;

create procedure test(in dbName varchar(40))
begin

set @query := CONCAT("SELECT * FROM " , dbName, ".db;");

PREPARE s from @query;

EXECUTE s;
DEALLOCATE PREPARE s;

end;;

delimiter ;

call test("mysql"); 
票数 2
EN

Stack Overflow用户

发布于 2010-01-15 15:15:34

尝试在不同的过程中使用预准备语句创建(临时)表。

代码语言:javascript
复制
SET @query = CONCAT("CREATE TABLE temp_table AS SELECT cdrs_id, called, calling FROM "     ,dbName, ".cdrs WHERE lrn_checked = 'N' ");

..。

然后在“测试”过程中从该表中选择数据。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1680850

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档