根据 MySQL / MariaDB 中的新序列更新主键值
update primary key values based on a new sequence in MySQL / MariaDB
考虑一个 table my_table
,其中列 id_my_table
作为主键并自动递增
CREATE TABLE `my_table` (
`id_my_table` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`some_name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id_my_table`)
) ENGINE=InnoDB;
该主键被其他 table 引用。
我有一些记录,为了这个例子,假设我有五个 id_my_table
以下值:1、2、3、4 和 5。由于客户的请求,这涉及到从旧数据集中获取特定序列,我更新了主键的值以匹配该序列。
这是我所做的:
ALTER TABLE `my_table` ADD COLUMN `my_old_id` INT UNSIGNED NULL AFTER `some_name`;
UPDATE `my_table` set `my_old_id` = `id_my_table`;
SET FOREIGN_KEY_CHECKS=0;
-- +100 so no duplicate error...
UPDATE `my_table` set `id_my_table` = `id_my_table` + 100;
UPDATE `my_table` set `id_my_table` = 25 where `id_my_table` = 1;
UPDATE `my_table` set `id_my_table` = 37 where `id_my_table` = 2;
UPDATE `my_table` set `id_my_table` = 58 where `id_my_table` = 3;
UPDATE `my_table` set `id_my_table` = 72 where `id_my_table` = 4;
UPDATE `my_table` set `id_my_table` = 96 where `id_my_table` = 5;
ALTER TABLE `my_table` AUTO_INCREMENT = 97;
UPDATE another_table at
INNER JOIN my_table mt on mt.my_old_id = at.reference_to_id_my_table
SET at.reference_to_id_my_table = mt.id_my_table;
SET FOREIGN_KEY_CHECKS=1;
现在一切都按预期工作,新记录的顺序正确(基于旧记录),但是...
我可以正常继续吗?还是我搞砸了一些内部索引,但我没有发现潜在的问题?
简短回答:看起来不错。
长答案:
测试的“正确”方法是将所有相关的table复制到另一台服务器(或在同一台服务器上,但在不同的数据库中).然后执行诸如通过外键获取或添加新行(将获得 id=97)之类的操作。
还有一件事要做:将 START TRANSACTION
和 COMMIT
放在 UPDATEs
的周围。此单个事务将确保所有更新或未完成。
顺便说一句,我看不出你的代码有什么问题。 (我假设 Update with the Join 将针对引用 my_table
的彼此 table 完成。)(如果您已经 运行 所有 Update,请不要担心事务。将其视为 'next time' 的提示。)
至于 AUTO_INCREMENT
的工作原理,我看不出有任何未来的陷阱。新 ID 为 97 及以上;缺口中的数字将永远消失。
请注意 REPLACE
是 DELETE
+ INSERT
,因此在所有(?)情况下,它都会丢失 auto_inc id。
你必须写5个更新吗?使用映射构建 table,然后将其应用于所有相关的 table 可能更容易。在主要table的情况下,只有存在重复ID的风险,您是否需要一些技巧(例如+100)。
以后考虑DROP COLUMN
。
考虑一个 table my_table
,其中列 id_my_table
作为主键并自动递增
CREATE TABLE `my_table` (
`id_my_table` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`some_name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id_my_table`)
) ENGINE=InnoDB;
该主键被其他 table 引用。
我有一些记录,为了这个例子,假设我有五个 id_my_table
以下值:1、2、3、4 和 5。由于客户的请求,这涉及到从旧数据集中获取特定序列,我更新了主键的值以匹配该序列。
这是我所做的:
ALTER TABLE `my_table` ADD COLUMN `my_old_id` INT UNSIGNED NULL AFTER `some_name`;
UPDATE `my_table` set `my_old_id` = `id_my_table`;
SET FOREIGN_KEY_CHECKS=0;
-- +100 so no duplicate error...
UPDATE `my_table` set `id_my_table` = `id_my_table` + 100;
UPDATE `my_table` set `id_my_table` = 25 where `id_my_table` = 1;
UPDATE `my_table` set `id_my_table` = 37 where `id_my_table` = 2;
UPDATE `my_table` set `id_my_table` = 58 where `id_my_table` = 3;
UPDATE `my_table` set `id_my_table` = 72 where `id_my_table` = 4;
UPDATE `my_table` set `id_my_table` = 96 where `id_my_table` = 5;
ALTER TABLE `my_table` AUTO_INCREMENT = 97;
UPDATE another_table at
INNER JOIN my_table mt on mt.my_old_id = at.reference_to_id_my_table
SET at.reference_to_id_my_table = mt.id_my_table;
SET FOREIGN_KEY_CHECKS=1;
现在一切都按预期工作,新记录的顺序正确(基于旧记录),但是...
我可以正常继续吗?还是我搞砸了一些内部索引,但我没有发现潜在的问题?
简短回答:看起来不错。
长答案:
测试的“正确”方法是将所有相关的table复制到另一台服务器(或在同一台服务器上,但在不同的数据库中).然后执行诸如通过外键获取或添加新行(将获得 id=97)之类的操作。
还有一件事要做:将 START TRANSACTION
和 COMMIT
放在 UPDATEs
的周围。此单个事务将确保所有更新或未完成。
顺便说一句,我看不出你的代码有什么问题。 (我假设 Update with the Join 将针对引用 my_table
的彼此 table 完成。)(如果您已经 运行 所有 Update,请不要担心事务。将其视为 'next time' 的提示。)
至于 AUTO_INCREMENT
的工作原理,我看不出有任何未来的陷阱。新 ID 为 97 及以上;缺口中的数字将永远消失。
请注意 REPLACE
是 DELETE
+ INSERT
,因此在所有(?)情况下,它都会丢失 auto_inc id。
你必须写5个更新吗?使用映射构建 table,然后将其应用于所有相关的 table 可能更容易。在主要table的情况下,只有存在重复ID的风险,您是否需要一些技巧(例如+100)。
以后考虑DROP COLUMN
。