我需要在游标的声明中使用一个变量来指示要查询的数据库。以下是代码的一小段:
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不会允许这样做。我还尝试了一些东西,比如:
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语句。
有没有人能想出一种方法,通过传入应该受到影响的数据库的名称,在多个数据库中使用相同的存储过程?
发布于 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命令时停止。
下面是我的例子:
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$$发布于 2009-11-05 23:44:34
不,您不能在游标中这样做。也许准备好的语句就可以完成这项工作?:
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"); 发布于 2010-01-15 15:15:34
尝试在不同的过程中使用预准备语句创建(临时)表。
SET @query = CONCAT("CREATE TABLE temp_table AS SELECT cdrs_id, called, calling FROM " ,dbName, ".cdrs WHERE lrn_checked = 'N' ");..。
然后在“测试”过程中从该表中选择数据。
https://stackoverflow.com/questions/1680850
复制相似问题