Non c'è un modo semplice per aggirare il comportamento predefinito dell'attributo AUTO_INCREMENT
in MySQL, e anche se si trova un modo, io non mi consiglia di farlo, dal momento che è il modo migliore per incorrere in problemi nel breve termine. I valori AUTO_INCREMENT
non devono essere modificati o resettati in un ambiente di produzione.
Una possibile soluzione al tuo problema potrebbe essere quella di denormalizzare un po 'il tuo modello. L'idea è di spostare il campo AUTO_INCREMENT
in una tabella laterale in cui non è necessario copiare o eliminare righe. Tutto quello che devi fare è ottenere un nuovo valore id da questa tabella laterale quando crei un nuovo elemento e mantieni il valore id esistente quando copi le righe da una tabella a un'altra.
Per raggiungere questo obiettivo verrà utilizzato un trigger che creerà un nuovo ID per noi e assegnarlo al nostro record di articolo. Il campo id della tabella degli articoli deve essere annullabile affinché funzioni, quindi dobbiamo sostituire la chiave primaria con un indice univoco.
Questo cambiamento modello sarebbe completamente trasparente per l'applicazione, in modo da non avrebbe alcun cambiamento per rendere nel codice dell'applicazione.
Ecco alcuni esempi di script. Diciamo che abbiamo due tavoli voce nel database con alcune righe comuni, e alcune righe che devono essere spostati dal primo tavolo a seconda tabella:
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);
Se proviamo a spostare alcuni dati da una tabella all'altra e quindi riavviare il server, riscontreremo il problema del ripristino dei valori AUTO_INCREMENT
. Quindi dovremo modificare leggermente il nostro modello come segue:

si procederà in più fasi per migrare il nostro modello di dati. Le istruzioni DDL nei seguenti script di migrazione sono state generate utilizzando l'IDE neXtep Designer.
- Per prima cosa creare una nuova tabella item_keys che conterrà il 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);
- Ma prima di attivare l'attributo
AUTO_INCREMENT
, dobbiamo inserire gli ID esistenti nella nostra nuova tabella:
-- 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
;
- Ora possiamo attivare l'attributo
AUTO_INCREMENT
, e inizializzare il suo valore per inserti futuri:
-- 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;
- Poi possiamo modificare le tabelle
item1
e item2
per sostituire la chiave primaria per un indice univoco, e riferimento alla chiave primaria della tabella 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)
;
- Infine, non ci resta che creare i trigger che gestiranno la creazione ids per noi:
-- 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;
|;
Ora possiamo spostare i dati da un tavolo all'altro, mantenendo inalterate le ids, e se riavviamo il server, il valore AUTO_INCREMENT
nello item_keys
rimarrà lo stesso.
--------------
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 non è una versione, è un'intera famiglia di versioni. Si prega di fornire tutte e tre le cifre della versione. Se non lo sai, fai 'mostra variabili come '% versione%'' – derobert
Inoltre, * Ho bisogno di regolare i valori di incremento automatico ... all'avvio dell'applicazione * mi sembra che * stai facendo male *. – derobert
Perché su ogni forum c'è un ragazzo, che sa esattamente di quanto sto facendo male ??? :) –