2012-12-11 34 views
2

問題描述迭代MySQL模式

我有一個單租戶MySQL數據庫的設置。也就是說,每個客戶端都有一個相同的模式。

現在我需要爲每個客戶運行一個特定的查詢。在多租戶設置中(所有客戶端共享單個模式)這很容易。但是,使用我的設置,我需要迭代模式。 更一般地說,我想訪問一個名稱由變量給出的模式。這怎麼做?

我已經試過

  • 如果我嘗試USE varSchemaName(其中varSchemaNamevarchar 變量),我得到錯誤信息錯誤1314:USE是不允許 在存儲過程

  • 如果我嘗試SELECT * FROM varSchemaName.MyTable我得到 錯誤代碼:1146表「varSchemaName.MyTable」不存在。顯然MySQL認爲varSchemaName是一個文字,而不是一個 變量。

回答

2

您必須先建立聲明。

SET @sql = CONCAT('SELECT * FROM ', varSchemaName, '.MyTable'); 
PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

您可以閱讀更多有關準備語句here

您可能想使用表名變量,但這不起作用。這些參數適用於where子句等的值。上述方式是要走的路。

+0

謝謝,我只是試驗了這個自己,它似乎工作。如果我的查詢冗長而複雜,是否有更好的方法來聲明'@ sql'變量而不是將SQL代碼粘貼到字符串中呢? – Gruber

+1

我害怕,不,沒有更好的辦法。 – fancyPants

+0

我發現使用這種方法,您可以查詢單租戶數據庫設置,就像它是多租戶一樣。這非常強大,並將爲我解決很多麻煩。不幸的是,它不能用來發出'CREATE'語句。 – Gruber

1

建立在fancyPants的答案上,您可以在另一個查詢information_schema.tables的循環中調用該過程,以識別包含MyTable的數據庫,然後使用db名稱作爲參數調用fancyPants的過程。如果數據庫具有一致的命名方案或包含名稱相同的對象,則此方法非常簡單,這聽起來就像這裏的情況。結構會是這樣的:

DELIMITER // 

DROP PROCEDURE IF EXISTS mydriver // 
CREATE PROCEDURE mydriver() 
BEGIN 

    DECLARE varSchemaName VARCHAR(64); 
    DECLARE done BOOLEAN; 
    DECLARE cur CURSOR FOR 
    SELECT table_schema 
    FROM information_schema.tables 
    WHERE table_name = 'MyTable'; 

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 

    OPEN cur; 
    read_loop: LOOP 
     FETCH cur INTO varSchemaName; 
     IF done THEN 
     LEAVE read_loop; 
     CLOSE cur; 
     END IF; 

     CALL fancypants_proc(varSchemaName); 

    END LOOP; 
END // 

DROP PROCEDURE IF EXISTS fancypants_proc // 
CREATE PROCEDURE fancypants_proc(IN varSchemaName VARCHAR(64)) 
BEGIN 

    SET @sql = CONCAT('SELECT * FROM ', varSchemaName, '.MyTable'); 
    PREPARE stmt FROM @sql; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

END // 

DELIMITER ; 

CALL mydriver();