开发者

MySQL Stored Procedures : Use a variable as the database name in a cursor declaration

I need to use a variable to indicate what database to query in the declaration of a cursor. Here is a short snippet of the code :

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;

As you can see, I'm TRYING to use the variable dbName to indicate in which database the query should occur within. However, MySQL will NOT allow that. I also tried things such as :

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;

Of course this doesn't work either 开发者_运维技巧as MySQL only allows a standard SQL statement in the cursor declaration.

Can anyone think of a way to use the same stored procedure in multiple databases by passing in the name of the db that should be affected?


The answer of Vijay Jadhav is the right way to solve this limitation by MySQL. Actually, you need 3 proc to accomplish it:

proc1 using Vijay Jadhav's way, works like a data collector. You need to pass the variables to proc1 and let it create the tmp table for proc2. There is one limiation of Vijay's way, he should create a TEMPORARY table by using "CREATE TEMPORARY TABLE tmp_table_name SELECT ...". Because temporary table is thread safe.

proc2 declare the cursor on the tmp table which is created by proc1. Since the tmp table is already known and hard coded into the declaration, no more "table not found" error.

proc3 works like a "main" function, with all the parameters need to be sent to proc1 and proc2. proc3 simply calls proc1 first and then proc2 with the parameters need by each proc.

p.s Need to set system variable "sql_notes" to 0, otherwise proc1 will stop on DROP TABLE command.

Here is my example:

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$$


No, you can't do that in cursors. Maybe just prepared statements may do the job? :

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"); 


Try to create (temporary) table using prepared statement in a different procedure.

SET @query = CONCAT("CREATE TABLE temp_table AS SELECT cdrs_id, called, calling FROM "     ,dbName, ".cdrs WHERE lrn_checked = 'N' ");

...

And then select data from that table in your 'test' procedure.


The answer to this is that it cannot be done. You cannot use variables in the cursor declaration. I appreciate noonex's response. However, his solution does not allow me to walk through the results. It simply executes the query.


create procedure test(in dbName varchar(40)) READS SQL DATA <- this line returns will allow you to walk through the results begin ... $result = call test("mysql");

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜