【问题标题】:Merging two SQL tables with key conflicts合并两个有键冲突的 SQL 表
【发布时间】:2016-05-15 22:25:54
【问题描述】:

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

注意事项:

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

  2. 其余的合并我可以处理。两个表都包含有用的数据,当重复超出该范围的键时,我会将版本保留在表 A 中。

【问题讨论】:

  • 如果可以,请提供您现在正在尝试的查询,以便我们可以解决一些问题。然而,作为一个简短的回答,在您选择的Table B 中,您可以:select Id + 3000, col2, col3, col4 from TableB。 - 也就是说,如果Id 列是数字。
  • 我还没有查询——我不确定要采取哪种方法。我想过做一个UPDATE 为块中的每个 id 添加 1000,但我想我会问是否有更合适的方法。
  • 好的,我将把我的评论移到一个答案上,然后再添加一些想法。
  • 任何答案对您有帮助吗?不幸的是,不太可能会有更具体的内容... =(
  • 不是特别...我现在正在检查,但是当我有更多时间时,我必须仔细看看。

标签: mysql merge


【解决方案1】:

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

【讨论】:

  • 谢谢——我能想到许多可以解决冲突的映射(我宁愿加 1000)。我想我的问题是,我只是 UPDATE 这个 ID 块,还是有更好的方法/方法可用于这种事情?
【解决方案2】:

识别“重复”的 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】:

    从评论转到回答。

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

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

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

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

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

    另一个选项,如果您要将记录从Table B 插入到Table A,抛开Table B 中可能存在的孤立子记录问题,您可以省略Table B 中的IdSELECT INTO TableA... 就像您执行插入时一样,将使用自动增量 ID 生成一个新的 Id 值。

    对于孤立子记录的问题,您还可以向 TableA 添加一个名为 TableBId 的新列,该列将容纳来自 TableB 的原始 Id,这将允许您仍然访问与TableB.Id。另一种选择是为同样的想法创建一个新的子表。这将防止您不得不更改您的 TableA 结构,但仍提供一些方法来保留对旧数据的访问权限。

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

    【讨论】:

    • 这听起来像是一个很好的建议,但你的动态方法不会将 ID 更改级联到相关表......所以这是一个非首发。表 A 将不再增长,因此可以安全地修改。
    • 您打算一次性完成吗?您是否在执行合并后停用其中一个表。或者这会是一个持续的、复制型的场景吗?至于对子记录的更改,这就是我所说的通过添加一个新列,或者理想情况下,添加一个包含新 Id 列的新查找表以及以前的已停用表 Id 列。
    【解决方案4】:

    如果你经常这样做,试试其他人描述的一些花哨的方法,如果它是一个计时器完成的事情,那就用简单的方法来做,并确保你不会破坏任何东西:

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

      update b set b.id = b.id + offset where b.id in (select id from a)

    • 修复两个表的 auto_increment(设置在最后一个条目后面)
    • 启用自动增量
    • 启用写入表 a 的脚本
    • 在尝试写入表 b 的脚本中产生错误消息,说明数据已与 a 合并(或者也只使用表 a)
    • 将表 b 重命名为 delete_after_2016_05_31_b

    呃,仍然指向表 b 的级联数据会发生什么?

    这只会将副本“移动”到新位置,同时确保没有人会从非重复范围内的备份中恢复已删除的数据。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-24
      • 1970-01-01
      • 1970-01-01
      • 2012-11-24
      • 2020-07-23
      • 1970-01-01
      • 2019-10-18
      • 2012-12-08
      相关资源
      最近更新 更多