完全不清楚为什么要“隐藏”执行删除的证据。这听起来真是个坏主意。我不喜欢传播错误信息。
理想主键的两个特征是: - 匿名(没有任何有用的信息,不管它的设置是什么) - 不可变的(一旦分配,就永远不会改变。)
但是,如果我们把整个讨论放在一边……
我可以回答一个稍微不同的问题(您可能会发现对您的特定情况有帮助的答案)
消除具有 AUTO_INCREMENT 的列中的值中的“间隙”的唯一方法是将列值从其当前值更改为连续的新值序列。如果有任何外键引用该列,则这些列中的值也需要更新,以保留关系。这可能会使表的当前 auto_increment 值高于 id 列的最大值,所以我也想重置它,以避免在下一次插入时出现“间隙”。
(我已经在开发和测试环境中对 auto_increment 值进行了重新排序,以“清理”查找表,并将某些表的 id 值移动到与其他表中的范围不同的范围......让我测试 SQL以确保 SQL 连接谓词不会无意中引用错误的表,并意外返回看起来正确的行......这些是我在 auto_increment 值时重新分配的一些原因)
请注意,当您更改主键值时,数据库可以“自动”更新外键值(对于 InnnoDB 表),只要外键约束是用 定义的ON UPDATE CASCADE
,并且FOREIGN_KEY_CHECKS
未被禁用。
如果没有要处理的外键,并假设 id 的所有当前值都是正整数,那么我已经能够做这样的事情:(有适当的备份,所以如果事情没有,我可以恢复工作不正常)
UPDATE mytable t
JOIN (
SELECT s.id AS old_id
, @i := @i + 1 AS new_id
FROM mytable s
CROSS
JOIN (SELECT @i := 0) i
ORDER BY s.id
) c
ON t.id = c.old_id
SET t.id = c.new_id
WHERE t.id <> c.new_id
要将表 AUTO_INCREMENT 重置为表中最大的 id 值:
ALTER TABLE mytable AUTO_INCREMENT = 1;
c
通常,我将创建一个表并从上面的内联视图(别名为)中的该查询填充它。然后我可以使用该表来更新外键列和主键列,首先禁用 FOREIGN_KEY_CHECKS 然后重新启用它。(在并发环境中,其他进程可能正在从其中一个表中插入/更新/删除行,我当然会首先获得所有要更新的表的排他锁。)
再次提起我之前搁置的讨论……这种类型的“管理”功能在测试环境中非常有用,在设置测试用例时。但这不是在生产环境中使用实时数据执行的功能。