No hay una forma sencilla de evitar el comportamiento predeterminado de atributo AUTO_INCREMENT
en MySQL, e incluso si encuentra una forma, no lo recomendaría, ya que es la mejor manera de tener problemas en el término corto. Los valores AUTO_INCREMENT
no están destinados a ajustarse o reiniciarse en un entorno de producción.
Una posible solución a su problema podría ser desnormalizar un poco su modelo. La idea es mover el campo AUTO_INCREMENT
a una tabla lateral donde no tiene que copiar o eliminar filas. Todo lo que tiene que hacer entonces es obtener un nuevo valor de identificación de esta tabla auxiliar cuando crea un nuevo elemento, y mantener el valor de identificación existente al copiar las filas de una tabla a otra.
Para lograr esto, utilizaremos un disparador que creará una nueva identificación para nosotros y la asignará a nuestro registro de artículos. El campo id de la tabla de elementos tiene que ser anulable para que esto funcione, por lo que debemos reemplazar la clave principal por un índice único.
Este cambio de modelo sería completamente transparente para su aplicación, por lo que tendría ningún cambio a realizar en el código de aplicación.
Aquí hay algunos scripts de ejemplo. Supongamos que tenemos dos tablas de artículos en nuestra base de datos, con algunas filas comunes, y algunas filas que deben ser movido de primera tabla de la segunda tabla:
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);
Si tratamos de mover algunos datos de una tabla a otra y luego reinicie su servidor, nos encontraremos con el problema de AUTO_INCREMENT
restablecimiento de valor. Así que vamos a modificar ligeramente nuestro modelo de la siguiente manera:

procederemos en varios pasos para migrar nuestro modelo de datos. Las declaraciones DDL en los siguientes scripts de migración se han generado utilizando neXtep Designer IDE.
- En primer lugar, crear una nueva tabla item_keys que llevará a cabo el campo
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);
- Pero antes de activar el atributo
AUTO_INCREMENT
, hay que insertar los identificadores existentes en nuestra nueva tabla:
-- 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
;
- Ahora podemos activar el atributo
AUTO_INCREMENT
, e inicializar su valor para futuras inserciones:
-- 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;
- entonces podemos alterar las
item1
y item2
mesas para reemplazar la clave principal de un índice único, y referencia a la clave primaria de la tabla 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)
;
- Por último, sólo tenemos que crear los factores desencadenantes que se encargará de la creación de las identificaciones para nosotros:
-- 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;
|;
Ahora podemos mover datos de una tabla a otra, manteniendo los identificadores sin cambios, y si reiniciamos el servidor, el valor AUTO_INCREMENT
en item_keys
se mantendrá igual.
--------------
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 no es una versión, es una familia completa de versiones. Proporcione los tres dígitos de la versión. Si no lo sabe, 'muestre variables como '% version%' ' – derobert
Además, * Necesito ajustar los valores de incremento automático ... al inicio de la aplicación * me parece * que lo está haciendo mal *. – derobert
¿Por qué en cada foro hay un chico que sabe exactamente que lo estoy haciendo mal? :) –