Il modo in cui capisco la tua domanda è che hai una tabella esistente con una colonna che finora è stata popolata con valori manuali, e ora vuoi (1) rendere questa colonna una IDENTITY
colonna e (2) assicurarti che gli IDENTITY
inizi dal valore più recente nelle righe esistenti.
Prima di tutto, alcuni dati di test con cui giocare:
CREATE TABLE dbo.ident_test (
id int NOT NULL,
xyz varchar(10) NOT NULL,
CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id)
);
INSERT INTO dbo.ident_test (id, xyz)
VALUES (1, 'test'),
(2, 'test'),
(5, 'test'),
(6, 'test'),
(10, 'test'),
(18, 'test'),
(19, 'test'),
(20, 'test');
L'obiettivo è creare la colonna chiave primaria della tabella id
, una IDENTITY
colonna che inizierà alle 21 per il record successivo che verrà inserito. Per questo esempio, la colonna xyz
rappresenta tutte le altre colonne della tabella.
Prima di fare qualsiasi cosa, leggi gli avvisi in fondo a questo post.
Prima di tutto, nel caso in cui qualcosa vada storto:
BEGIN TRANSACTION;
Ora, aggiungiamo una colonna di lavoro temporanea id_temp
e impostiamo quella id
colonna sui valori della colonna esistente :
ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;
Successivamente, dobbiamo eliminare la id
colonna esistente (non puoi semplicemente "aggiungere" una IDENTITY
colonna esistente, devi creare la colonna come IDENTITY
). Anche la chiave primaria deve andare, perché la colonna dipende da essa.
ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;
... e aggiungi nuovamente la colonna, questa volta come IDENTITY
, insieme alla chiave primaria:
ALTER TABLE dbo.ident_test ADD id int IDENTITY(1, 1) NOT NULL;
ALTER TABLE dbo.ident_test ADD CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id);
Ecco dove diventa interessante. È possibile abilitare IDENTITY_INSERT
sulla tabella, il che significa che è possibile definire manualmente i valori di una IDENTITY
colonna quando si inseriscono nuove righe (non aggiornando le righe esistenti, però).
SET IDENTITY_INSERT dbo.ident_test ON;
Con quel set, DELETE
tutte le righe nella tabella, ma le righe che stai eliminando si trovano OUTPUT
nella stessa tabella, ma con valori specifici per la id
colonna (dalla colonna di backup).
DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);
Una volta fatto, IDENTITY_INSERT
spegnere di nuovo.
SET IDENTITY_INSERT dbo.ident_test OFF;
Rilascia la colonna temporanea che abbiamo aggiunto:
ALTER TABLE dbo.ident_test DROP COLUMN id_temp;
E infine, ridimensionato la IDENTITY
colonna, quindi i record successivi id
riprenderanno dopo il numero più alto esistente nella id
colonna:
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
Controllando la tabella di esempio, il id
numero più alto è 20.
SELECT * FROM dbo.ident_test;
Aggiungi un'altra riga e controlla la sua nuova IDENTITY
:
INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;
Nell'esempio, la nuova riga avrà id=21
. Infine, se sei soddisfatto, esegui la transazione:
COMMIT TRANSACTION;
Importante
Questa non è un'operazione banale e comporta alcuni rischi di cui dovresti essere consapevole.
Fallo in un ambiente di test dedicato. Avere backup. :)
Mi piace usare BEGIN/COMMIT TRANSACTION
perché impedisce ad altri processi di scherzare con il tavolo mentre sei nel mezzo di cambiarlo, e ti dà la possibilità di ripristinare tutto se qualcosa va storto. Tuttavia, qualsiasi altro processo che tenta di accedere al tuo tavolo prima di aver eseguito il commit della transazione finirà per attendere. Questo può essere piuttosto negativo se si dispone di una tabella di grandi dimensioni e / o ci si trova in un ambiente di produzione.
OUTPUT .. INTO
non funzionerà se la tabella di destinazione presenta vincoli di chiave esterna o una qualsiasi delle altre funzionalità che non ricordo dalla parte superiore della mia testa. È possibile invece scaricare i dati in una tabella temporanea e quindi reinserirli nella tabella originale. Potresti essere in grado di utilizzare il cambio di partizione (anche se non usi le partizioni).
Esegui queste istruzioni una per una, non come un batch o in una stored procedure.
Prova a pensare ad altre cose che potrebbero dipendere dalla id
colonna che stai abbandonando e ricreando. Eventuali indici dovranno essere eliminati e ricreati (come abbiamo fatto con la chiave primaria). Ricorda di scrivere ogni indice e vincolo che dovrai ricreare in anticipo.
Disabilita qualsiasi INSERT
e DELETE
trigger sul tavolo.
Se ricreare la tabella è un'opzione:
Se ricreare la tabella è un'opzione per te, tutto è molto più semplice:
- Crea la tabella vuota, con la
id
colonna come IDENTITY
,
- Apparecchiato
IDENTITY_INSERT ON
per il tavolo,
- Popolare il tavolo,
- Set
IDENTITY_INSERT OFF
e
- Ridistribuito l'identità.
IDENTITY
?