我正在使用已经使用多年的旧数据库,并且设计非常糟糕。 有一个表“文章”,其中包含一个“代码”列,它将成为我们的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'不存在”错误:)有什么想法吗?
答案 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