2011-08-08 81 views
2

我正在研究一個已經使用了多年的舊數據庫,並且設計得非常糟糕。 有一張表,「文章」,其中包含一個「代碼」列,將成爲我們的PK。 許多表像「idXXXXX」,其中XXXXX是一個「代碼」值,具有完全相同的結構。 我看着使用這個數據庫的應用程序,看到表之間的關係在那裏。在一個MYSQL中加入所有具有相同結構的表格

我並不擔心重新設計應用程序中的數據庫訪問權限,但我不想在數據庫中丟失多年的條目。

我想創建一個「campain」表,這將有一個「id」 PK和「id_code」爲FK鏈接「campain」到「文章」

我不是一個SQL高手,但我知道我可以得到表名

SELECT TABLE_NAME FROM INFORMATION_SCHEMA WHERE TABLE_NAME LIKE 'id%' 

但我真的不知道如何處理結果(這很好)。 那麼我怎樣才能訪問名爲「idXXX」的每個表格,並在「campain」表格中插入每一行+將「id_code」列設置爲「XXX」?


這裏是我救的程序(我沒有在INSERT行添加每場用於測試目的):

CREATE PROCEDURE JoinAllTables() 
BEGIN 

DECLARE done INT default 0; 
DECLARE tableName CHAR(9); 
DECLARE buffStr CHAR(7); 
DECLARE buffId INT default 0; 

DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'id%'; 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 


OPEN cur1; 

read_loop: LOOP 
    FETCH cur1 INTO tableName; 
    IF done THEN 
     LEAVE read_loop; 
    END IF; 

    SET buffStr = SUBSTRING(tableName, 3); 
    SET buffId = CAST(buffStr AS SIGNED); 

    set @sql = CONCAT("INSERT INTO campagnes(id, id_code) SELECT null, bufId FROM ",tableName); # Dynamically building sql statement 
    PREPARE stmt FROM @sql; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

    END LOOP; 
    CLOSE cur1; 
END; 

就像你看到的,我子「idXXXXX」到「XXXXX '然後把它整理(簽名)。 但我想在「INSERT INTO」一行中,第二個tableName不指向該變量。這就是爲什麼我得到一個 「#1446 - Tabble'bddsoufflage.tablename'doesn't exist」錯誤:)任何想法?

回答

4

編輯:更新回答

我們不能在預處理語句內動態更改tableName,因此我們必須通過DynamicSQL來使用CONCAT構建查詢,然後使用PREPARE編譯SQL,執行它並將其解除鎖定。

DELIMITER // 
CREATE PROCEDURE JoinAllTables() 
BEGIN 

DECLARE done INT default 0; 
DECLARE tableName CHAR(9); 
DECLARE buffStr CHAR(7); 
DECLARE buffId INT default 0; 

DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'id%'; 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 

OPEN cur1; 

read_loop: LOOP 
    FETCH cur1 INTO tableName; 
    IF done THEN 
     LEAVE read_loop; 
    END IF; 

    SET buffStr = SUBSTRING(tableName, 3); 
    SET buffId = CAST(buffStr AS SIGNED); 

    set @sql = CONCAT("INSERT INTO campagnes(id, id_code) SELECT null, ", buffId, " FROM ",tableName); # Dynamically building sql statement 
    PREPARE stmt FROM @sql; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

    END LOOP; 
    CLOSE cur1; 
END; // 

也看到這個答案MySQL Pass table name to cursor select

老答案 的程序應該是這個樣子。感謝Mchl提供了一個Insert Into查詢示例,我只是將它添加到該過程的其餘部分。

DELIMITER // 
CREATE PROCEDURE JoinAllTables() 
BEGIN 

DECLARE done INT default 0; 
DECLARE tableName CHAR(7); # Variable to contain table names CHAr(7) is assuming id + 5Xs as characters. 

DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM INFORMATION_SCHEMA WHERE TABLE_NAME LIKE 'id%'; # Create a cursor to iterate over the tables 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; 

OPEN cur1; 

read_loop: LOOP 
    FETCH cur1 INTO tableName; 
    IF done THEN 
     LEAVE read_loop; 
    END IF; 

    #Your Insert statement here, using tableName as a field. 
INSERT INTO campain (id, id_code, otherfields) SELECT null, tableName, otherfields FROM tableName; 

    END LOOP; 
    CLOSE cur1; 
END;// 
+0

非常感謝,我會嘗試,但在MYSQL中,我不會我認爲我可以使用像「idXXXX」這樣的字段作爲PK,也許我應該刪除「id」部分並將「XXXX」轉換爲INT? – Semtex

+0

是的,您可能想要重新處理tableName到其他的東西,使用SUBSTRING()函數來提取XXX,然後使用CAST()函數將其轉換爲數字。 – NetSquirrel

+0

我發現了一個錯誤,在第4行= /(DECLARE表名CHAR(7);)談論語法錯誤附近「」這是很奇怪,因爲我試圖刪除整條生產線(在壞的複製/粘貼的情況下),它什麼也沒變。 – Semtex

1

最簡單的方法是運行你有一些腳本(PHP,Python和Perl的 - 哪個適合你)內的INFORMATION_SCHEMA查詢,並使用它的結果來創建這樣的查詢:

INSERT INTO 
    campain (id, id_code, otherfields) 
SELECT 
    null, 'idXXXX', otherfields FROM idXXXX 
+0

哼我會嘗試一下,但沒有辦法在純SQL中做到這一點? – Semtex

+0

有,見@ NetSquirell的答案;)我只是不喜歡像這樣寫入存儲的特效; P – Mchl

+0

謝謝我在上面;) – Semtex

相關問題