合并两个带有键冲突的SQL表

时间:2016-05-15 22:25:55

标签: mysql merge

我正在尝试合并(联合)具有相同结构的两个表。在已知的行块中,主键(auto_increment整数)在两个表中用于不同的数据。让我们说它是主键2000-2150的行。将表B中的这些记录重新编号为未使用的值(例如,在3000以上的范围内)的最佳方法是什么,以便合并可以在没有冲突的情况下进行?我应该在适当的位置更新它们(例如,通过在该范围内为每个ID添加1000),还是有更好的方法?

注意:

  1. 此表的所有引用都声明为ON UPDATE CASCADE,因此我可以安全地对它们重新编号而不会产生任何后果。

  2. 我可以处理合并的其余部分。两个表都包含有用的数据,当重复该范围之外的密钥时,我将保留表A中的版本。

4 个答案:

答案 0 :(得分:0)

将数字更改为数字的负数将起作用。现在或将来都不会发生碰撞。

答案 1 :(得分:0)

从评论转到答案。

如果可以的话,请提供您正在尝试的查询,以便我们可以解决一些问题。但作为一个简短的答案...

在您选择的表B中,您可以:

select Id, col2, col3, col4
from TableA
union all
select Id + 3000, col2, col3, col4 
from TableB;

也就是说,如果Id列是数字。

有一点需要注意,如果您打算尝试将这些记录插入Table A,则需要禁用自动排序。

另一种选择,如果您要将记录从Table A插入Table B,将Table B中孤立子记录的可能问题放在一边,则可以省略{{1} Id上的Table B列,与插入时一样,将使用自动增量ID生成新的SELECT INTO TableA...值。

对于孤儿子记录问题,您还可以向名为Id的{​​{1}}添加一个新列,该列将包含来自TableA的{​​{1}}原始TableBId仍然可以访问与Id相关联的旧数据。另一种选择是针对同一想法的新子表。这样可以防止您改变TableB结构,但仍然提供一些方法来保留对旧数据的访问权。

如果你有更多关于你最想做什么的信息,我们可能会提出一个更好的解决方案,但这应该让你开始。

答案 2 :(得分:0)

识别"重复"

的ID值
 SELECT b.id
   FROM b
   JOIN a
     ON b.id = a.id

识别新的" id"值

SELECT MAX(m.id)
  FROM ( SELECT MAX(ma.id) AS id
           FROM a ma
          UNION ALL
         SELECT MAX(mb.id) AS id
           FROM b mb
       ) m     

生成新的"未使用的" id值

 SELECT s.id           AS old_id
      , @id := @id + 1 AS new_id 
   FROM ( SELECT b.id
            FROM b
            JOIN a
              ON b.id = a.id
           ORDER BY b.id 
        ) s
 CROSS
  JOIN ( SELECT @id := MAX(ma.id) FROM a ma) i 
 ORDER
    BY s.id 

执行更新

 UPDATE b t
   JOIN ( SELECT r.*
            FROM ( SELECT s.id           AS old_id
                        , @id := @id + 1 AS new_id 
                     FROM ( SELECT b.id
                              FROM b
                              JOIN a
                                ON b.id = a.id
                             ORDER BY b.id 
                          ) s
                   CROSS
                    JOIN ( SELECT @id = MAX(m.id)
                             FROM ( SELECT MAX(ma.id) AS id
                                      FROM a ma
                                     UNION ALL
                                    SELECT MAX(mb.id) AS id
                                      FROM b mb
                                  ) m     
                         ) i 
                   ORDER
                      BY s.id 
                 ) r
        ) q
     ON t.id = q.old_id
    SET t.id = q.new_id

答案 3 :(得分:0)

如果你经常这样做,尝试一些像其他人描述的花哨的方式,如果它是一个完成一个计时器的事情,只需这样做,并确保你不打破任何东西:

  • 创建mysql dump
  • 禁用写入a和b的脚本
  • 禁用auto_increment
  • 计算偏移量(来自b的最小ID - 来自+ 1的最大ID)
  • 修复b中的条目(如果级联有效)

    更新b set b.id = b.id + offset其中b.id in(从a中选择id)

  • 修复两个表的auto_increment(设置在最后一个条目后面)
  • 启用auto_increment
  • 启用写入表a的脚本
  • 在脚本中生成错误消息,尝试写入表b,解释数据已与a合并(或者只是使用表格)
  • 将表b重命名为delete_after_2016_05_31_b
呃,仍然指向表b的级联数据会发生什么?

这只是"移动"复制到新位置,还要确保没有人会在非重复范围内从备份中恢复已删除的数据。

另一种方法是按记录记录并将数据插入表a,然后使用mysqllastinsertid更新指向旧值的所有条目。

相关问题