2

カーソルの宣言でクエリするデータベースを示すために変数を使用する必要があります。コードの短いスニペットは次のとおりです。

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ステートメントしか許可しないため、これも機能しません。

影響を受けるデータベースの名前を渡すことで、複数のデータベースで同じストアドプロシージャを使用する方法を考えられる人はいますか?

4

5 に答える 5

8

Vijay Jadhavの答えは、MySQL によるこの制限を解決する正しい方法です。実際には、それを達成するには 3 つの proc が必要です。

Vijay Jadhav の方法を使用する proc1 は、データ コレクターのように機能します。変数を proc1 に渡して、proc2 の tmp テーブルを作成させる必要があります。Vijay の方法には 1 つの制限があり、「CREATE TEMPORARY TABLE tmp_table_name SELECT ...」を使用して TEMPORARY テーブルを作成する必要があります。一時テーブルはスレッドセーフであるためです。

proc2 は、proc1 によって作成された tmp テーブルでカーソルを宣言します。tmp テーブルは既に認識されており、宣言にハード コードされているため、「テーブルが見つかりません」というエラーは発生しません。

proc3 は「メイン」関数のように機能し、すべてのパラメーターを proc1 と proc2 に送信する必要があります。proc3 は、最初に proc1 を呼び出し、次に各 proc が必要とするパラメーターを指定して proc2 を呼び出します。

ps システム変数 "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$$
于 2011-04-05T15:16:53.600 に答える
2

別の手順でプリペアドステートメントを使用して(一時的な)テーブルを作成してみてください。

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

..。

次に、「テスト」手順でそのテーブルからデータを選択します。

于 2010-01-15T07:15:34.103 に答える
2

いいえ、カーソルではできません。たぶん、準備されたステートメントだけでうまくいくでしょうか?:

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"); 
于 2009-11-05T15:44:33.963 に答える
0

create procedure test(in dbName varchar(40)) READS SQL DATA <- この行を返すと、結果を確認できます begin ... $result = call test("mysql");

于 2014-12-02T16:11:05.963 に答える
0

これに対する答えは、それはできないということです。カーソル宣言では変数を使用できません。noonexの反応に感謝します。ただし、彼のソリューションでは、結果を確認することはできません。クエリを実行するだけです。

于 2009-11-10T21:13:55.737 に答える