在一个MYSQL中加入具有相同结构的所有表

时间:2011-08-08 12:58:24

标签: mysql

我正在使用已经使用多年的旧数据库,并且设计非常糟糕。 有一个表“文章”,其中包含一个“代码”列,它将成为我们的PK。 还有很多像“idXXXXX”这样的表,其中XXXXX是一个具有完全相同结构的“代码”值。 我使用这个数据库查看了应用程序,并看到了表之间的关系。

我并不担心在应用程序中重新设计数据库访问,但我不想在数据库中丢失多年的条目。

我想创建一个“campain”表,其中有一个“id”PK和一个“id_code”作为FK将“campain”链接到“articles”

我不是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'然后将其作为AS INTEGER(SIGNED)进行CAST。 但我想在“INSERT INTO”行中,第二个tableName不指向变量。这就是为什么我得到一个 “#1446 - Tabble'bddsoufflage.tablename'不存在”错误:)有什么想法吗?

2 个答案:

答案 0 :(得分:4)

修改:更新回答

我们不能在预准备语句中动态更改tableName,因此我们必须通过DynamicSQL使用CONCAT构建查询,然后使用PREPARE编译SQL,执行它并DEALLOCATE它。

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;//

答案 1 :(得分:1)

最简单的方法是运行一些脚本中的information_schema查询(PHP,Python,Perl - 最适合您的方法)并使用它的结果创建如下查询:

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