没有简单的方法来解决在MySQL中AUTO_INCREMENT
属性的默认行为,即使您找到了方法,我也不会建议您这样做,因为它是遇到问题的最佳方法短期。 AUTO_INCREMENT
值不意味着在生产环境中进行调整或重置。
您的问题的一个可能的解决方案可能是使您的模型稍微规范化。我们的想法是将AUTO_INCREMENT
字段移动到不需要复制或删除行的副表。您所要做的就是在创建新项目时从此旁边表格获取新的id值,并在将行从一个表格复制到另一个表格时保留现有的id值。
为了达到这个目的,我们将使用一个触发器为我们创建一个新的id并将其分配给我们的项目记录。项目表的id字段必须为空才能工作,所以我们必须用唯一索引替换主键。
这种模式的变化将是完全透明的为您的应用,所以你会没有改变在应用程序代码做。
以下是一些示例脚本。比方说,我们已经在我们的数据库中有两个项目表,一些常见的行和一些行需要从第一台到第二台移动:
CREATE TABLE `item1` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`item_res_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `item2` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`item_res_id` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO item1 (item_res_id) VALUES (1);
INSERT INTO item1 (item_res_id) VALUES (2);
INSERT INTO item2 (item_res_id) VALUES (1);
如果我们试图从一个表将一些数据到另一个然后重启你的服务器,我们会遇到AUTO_INCREMENT
值重置的问题。因此,我们将稍微修改我们的模型如下:

我们将分几个步骤进行,以将我们的数据模型。以下迁移脚本中的DDL语句已使用neXtep Designer IDE生成。
- 首先,我们创建一个新的item_keys表,将持有的
AUTO_INCREMENT
领域:
-- Creating table 'item_keys'
CREATE TABLE item_keys (
id BIGINT(20) UNSIGNED NOT NULL
,key_ctime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) Engine=InnoDB default charset=utf8;
-- Creating Primary Key constraint 'PRIMARY' on table 'item_keys'
ALTER TABLE item_keys ADD CONSTRAINT PRIMARY KEY (id);
- 但激活
AUTO_INCREMENT
属性之前,我们必须将现有的ID添加到我们的新表:
-- Initializing item_keys with existing ids
INSERT INTO item_keys (id)
SELECT i1.id
FROM item1 i1
LEFT JOIN item_keys ik ON ik.id = i1.id
WHERE ik.id IS NULL
;
INSERT INTO item_keys (id)
SELECT i2.id
FROM item2 i2
LEFT JOIN item_keys ik ON ik.id = i2.id
WHERE ik.id IS NULL
;
- 我们现在可以激活
AUTO_INCREMENT
属性,并为未来的刀片初始化它的价值:
-- Activating auto_increment constraint...
ALTER TABLE item_keys MODIFY id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
-- Initializing auto_increment value
SELECT @inc_value := MAX(id) FROM item_keys;
SET @alter_query = CONCAT('ALTER TABLE item_keys AUTO_INCREMENT=',@inc_value);
PREPARE alter_query FROM @alter_query;
EXECUTE alter_query;
DEALLOCATE PREPARE alter_query;
- 然后我们就可以改变
item1
和item2
表来代替由唯一索引主键,和引用item_keys表的主键:
-- De-activating auto_increment constraint...
ALTER TABLE item1 MODIFY id BIGINT(20) UNSIGNED NOT NULL;
-- Dropping constraint 'PRIMARY'...
ALTER TABLE item1 DROP PRIMARY KEY;
ALTER TABLE item1 MODIFY id BIGINT(20) UNSIGNED NULL;
-- Creating index 'item1_uk'...
CREATE UNIQUE INDEX item1_uk ON item1 (id);
-- Creating Foreign Key constraint 'item1_keys_fk' on table 'item1'
ALTER TABLE item1 ADD
CONSTRAINT item1_keys_fk FOREIGN KEY item1_keys_fk
(id) REFERENCES item_keys
(id)
;
-- De-activating auto_increment constraint...
ALTER TABLE item2 MODIFY id BIGINT(20) UNSIGNED NOT NULL;
-- Dropping constraint 'PRIMARY'...
ALTER TABLE item2 DROP PRIMARY KEY;
ALTER TABLE item2 MODIFY id BIGINT(20) UNSIGNED NULL;
-- Creating index 'item2_uk'...
CREATE UNIQUE INDEX item2_uk ON item2 (id);
-- Creating Foreign Key constraint 'item2_keys_fk' on table 'item2'
ALTER TABLE item2 ADD
CONSTRAINT item2_keys_fk FOREIGN KEY item2_keys_fk
(id) REFERENCES item_keys
(id)
;
- 最后,我们只需要创建将管理的ID创建为我们的触发器:
-- Creating trigger 'tr_item1_bi' on table 'item1'...
DELIMITER |;
CREATE TRIGGER tr_item1_bi BEFORE INSERT ON item1
FOR EACH ROW
BEGIN
IF (NEW.id IS NULL) THEN
-- If no item id has been specified in the INSERT statement, it
-- means we want to create a new item. We insert a new record
-- into the item_keys table to get an item id.
INSERT INTO item_keys (
key_ctime
)
VALUES (NOW());
SET NEW.id = LAST_INSERT_ID();
END IF;
END;
|;
-- Creating trigger 'tr_item2_bi' on table 'item2'...
DELIMITER |;
CREATE TRIGGER tr_item2_bi BEFORE INSERT ON item2
FOR EACH ROW
BEGIN
IF (NEW.id IS NULL) THEN
-- If no item id has been specified in the INSERT statement, it
-- means we want to create a new item. We insert a new record
-- into the item_keys table to get an item id.
INSERT INTO item_keys (
key_ctime
)
VALUES (NOW());
SET NEW.id = LAST_INSERT_ID();
END IF;
END;
|;
现在,我们可以从一个表将数据移动到另一个,保持IDS不变,如果我们重新启动服务器,item_keys
中的AUTO_INCREMENT
值将保持不变。
--------------
INSERT INTO item2
SELECT i1.*
FROM item1 i1
LEFT JOIN item2 i2
ON i2.id = i1.id
WHERE i2.id IS NULL
--------------
Query OK, 1 row affected (0.04 sec)
Records: 1 Duplicates: 0 Warnings: 0
--------------
DELETE FROM item1
--------------
Query OK, 2 rows affected (0.00 sec)
--------------
INSERT INTO item1 (item_res_id) VALUES (3)
--------------
Query OK, 1 row affected (0.00 sec)
--------------
SELECT * FROM item1
--------------
+------+-------------+
| id | item_res_id |
+------+-------------+
| 3 | 3 |
+------+-------------+
1 row in set (0.00 sec)
--------------
SELECT * FROM item2
--------------
+------+-------------+
| id | item_res_id |
+------+-------------+
| 1 | 1 |
| 2 | 2 |
+------+-------------+
2 rows in set (0.00 sec)
--------------
SELECT * FROM item_keys
--------------
+----+---------------------+
| id | key_ctime |
+----+---------------------+
| 1 | 2010-11-14 10:31:21 |
| 2 | 2010-11-14 10:31:21 |
| 3 | 2010-11-14 10:31:46 |
+----+---------------------+
3 rows in set (0.00 sec)
MySQL 5.0不是一个版本,它的一个完整的版本系列。请提供版本的全部三位数字。如果你不知道,请'显示像'%version%'这样的变量'' – derobert 2010-11-10 17:33:42
另外,*我需要调整自动递增值...在应用程序启动时*打击我*因为你做错了*。 – derobert 2010-11-10 17:54:27
为什么在每个论坛上都有一个人,谁知道我做错了? :) – 2010-11-10 20:13:34