MYSQL更新所有外键值

时间:2016-02-22 12:23:15

标签: mysql sql foreign-keys

我有两个相同的表位于两个相同的数据库(具有不同的名称)。我想合并这两个表,但它们的主键用于其他表,

这些表看起来像这样:

表A

id     column1     column2    column3
___    ________    _______    ________
 1        text        text      text
 2        text        text      text
 3        text        text      text   

表B

id     column1     column2    column3
___    ________    _______    ________
 2        text        text      text
 3        text        text      text
 4        text        text      text 

与表A相关联的表格

链接A

id     column1     tableA_ID
___    ________    _______  
 1        text        2     
 2        text        3      
 3        text        4   

链接B

id     column1     tableA_ID
___    ________    _______  
 1        text        3     
 2        text        3      
 3        text        2    

请注意,这些表具有相同的id,这意味着当我进行合并时,我必须更改第二个表的id。请记住第二个表的主键在其他表中使用。

我写了这个查询来合并两个表:

INSERT INTO db_A.`Table_A`(`column2`,`column3`) 
    SELECT `column2`,`column3` FROM db_B.`Table_B`; 

此查询将正确地将第二个表的记录复制到第一个表。

现在我想移动与Table B链接的表的数据,我可以使用相同的查询,但现在外键不匹配,因为它们被链接的ID已经改变了。

如何更新它们以便ID再次匹配?

注意:我对这些表没有ON UPDATE CASCADE约束

我希望这是有道理的,我会尝试改进这个问题,以便每个人都理解它。

数据库信息

Type  : MySQL
Engine: MyISAM

4 个答案:

答案 0 :(得分:3)

我的建议是:

  1. database1 中删除 LinkA 的外键约束
  2. 增加 TableA的外键:id AND LinkA:tableA_ID (最好的方法是使用连接)让我们说1000(或者你有多少行)在 database2
  3. 再次添加约束(可选)
  4. database1 导入 TableA 然后 LinkA database2
  5. 如果您需要更多帮助,请询问。

    最好的问候

    ====================================

    更新。更新ID的示例:

    UPDATE
        Table_A, Link_A 
    SET
        Table_A.id = Table_A.id + 1000, 
        Link_A.id  = Link_A.tableA_ID + 1000, 
    FROM
        Table_A JOIN Link_A 
    ON 
        Table_A.id = Link_A.tableA_ID
    

答案 1 :(得分:2)

如果两个db都相同,我相信你应该将它命名为db_B.Table_A而不是db_B.Table_B以避免混淆。但是现在我同意它

--get delta id, use biggest id from db_A and db_B 
--to avoid failure because of updating to existing primary key

SELECT @dbBMax := MAX(id) FROM db_B.`Table_B`;
SELECT @dbAMin := MIN(id), @dbAMax := MAX(id) FROM db_A.`Table_A`;
SET @DeltaID := IF(@dbBMax > @dbAMax, @dbBMax, @dbAMax) - @dbAMin + 1;

--drop constraint
ALTER TABLE db_A.`Link_A` DROP FOREIGN KEY `constraint_name_A`;
ALTER TABLE db_A.`Link_B` DROP FOREIGN KEY `constraint_name_B`;

--update ids
UPDATE db_A.`Table_A` SET id = id + @DeltaID;
UPDATE db_A.`Link_A` SET tableA_ID = tableA_ID + @DeltaID;
UPDATE db_A.`Link_B` SET tableA_ID = Link_A.tableA_ID + @DeltaID;

--merge tables 
--assume id is auto-increment, don't use auto-increment value, 
--so id manually inserted
INSERT INTO db_A.`Table_A`(`id`, `column1`, `column2`,`column3`) 
SELECT `id`, `column1`, `column2`,`column3` FROM db_B.`Table_B`;

--assume id is auto-increment, use it, don't insert manually     
INSERT INTO db_A.`Link_A`(`column1`, `tableA_ID`) 
SELECT `column1`, `tableA_ID` FROM db_B.`Link_A`;

--assume id is auto-increment, use it, don't insert manually     
INSERT INTO db_A.`Link_B`(`column1`, `tableA_ID`) 
SELECT `column1`, `tableA_ID` FROM db_B.`Link_B`;

如果id有更多可以修复db_B.Table_B的数据db_A.Table_A,此代码可能会在db_B.Table_B {{1}}添加跳跃合并表之前/之后很容易..但我认为它是可选的..

答案 2 :(得分:1)

一种简单的方法是将TableB的{​​{1}}更新为唯一范围,然后进行合并。如果您的外键已正确设置为级联更改,则数据库将通过此操作保持一致。

您不需要以这种方式对数据库模式进行任何更改,因此没有时间数据不是calid。您还可以确保ID不会发生冲突。查找唯一值的最简单方法是取IDID的最大值,并将其添加到TableA中的ID

答案 3 :(得分:1)

您可以将ON UPDATE CASCADE应用于第二个数据库临时与TableB.id相关的外键的每个表:

ALTER TABLE db2.other_tables_with_fk DROP FOREIGN KEY fk_to_TableB;

ALTER TABLE db2.other_tables_with_fk
  ADD CONSTRAINT fk_to_TableB FOREIGN KEY (TableB_id)
    REFERENCES TableB(id) ON UPDATE CASCADE;

然后使用Sami's Answer中的技巧,然后删除这样的临时更改:

ALTER TABLE db2.other_tables_with_fk DROP FOREIGN KEY fk_to_TableB;

ALTER TABLE db2.other_tables_with_fk
  ADD CONSTRAINT fk_to_TableB FOREIGN KEY (TableB_id)
    REFERENCES TableB(id);

然后你的第二个数据库就可以与第一个数据库合并了。

对于 MyISM 或引擎不支持CASCADE的情况,您可以通过定义Triggers手动模拟它:

CREATE TRIGGER trigger1
    AFTER UPDATE
    ON TableB
    FOR EACH ROW
BEGIN
    UPDATE other_tables_with_fk1 SET TableB_id = NEW.id WHERE TableB_id = OLD.id
    UPDATE other_tables_with_fk2 SET TableB_id = NEW.id WHERE TableB_id = OLD.id
    ...
END

即使触发器不可用,您也可以在所有表​​(包括同时使用外键父表)中,通过某个自定义量(任何大于第一个数据库中使用的最大行ID的数量)增加第二个数据库中的id行数:

UPDATE TableB t SET t.id = (t.id + 10000);
UPDATE related_table_1 t SET t.TableB_id = (t.TableB_id + 10000);
UPDATE related_table_2 t SET t.TableB_id = (t.TableB_id + 10000);
...

然后你可以合并这些数据库。