La façon dont je comprends votre question est que vous avez une table existante avec une colonne qui jusqu'à présent était remplie de valeurs manuelles, et maintenant vous voulez (1) faire de cette colonne une IDENTITY
colonne, et (2) vous assurer que le IDENTITY
début à partir de la valeur la plus récente des lignes existantes.
Tout d'abord, quelques données de test pour jouer avec:
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'objectif est de faire de la colonne de clé primaire de la table id
, unIDENTITY
colonne qui commencera à 21 pour le prochain enregistrement qui sera inséré. Pour cet exemple, la colonne xyz
représente toutes les autres colonnes de la table.
Avant de faire quoi que ce soit, veuillez lire les avertissements au bas de cet article.
Tout d'abord, en cas de problème:
BEGIN TRANSACTION;
Maintenant, ajoutons une colonne de travail temporaire id_temp
et définissons cette colonne sur les id
valeurs de la colonne existante :
ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;
Ensuite, nous devons supprimer la id
colonne existante (vous ne pouvez pas simplement "ajouter" un IDENTITY
à une colonne existante, vous devez créer la colonne en tant que IDENTITY
). La clé primaire doit également disparaître, car la colonne en dépend.
ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;
... et ajoutez à nouveau la colonne, cette fois sous la forme d'un IDENTITY
, avec la clé primaire:
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);
Voici où cela devient intéressant. Vous pouvez l'activer IDENTITY_INSERT
sur la table, ce qui signifie que vous pouvez définir manuellement les valeurs d'une IDENTITY
colonne lorsque vous insérez de nouvelles lignes (sans mettre à jour les lignes existantes, cependant).
SET IDENTITY_INSERT dbo.ident_test ON;
Avec cet ensemble, DELETE
toutes les lignes de la table, mais les lignes que vous supprimez sont OUTPUT
directement dans la même table - mais avec des valeurs spécifiques pour la id
colonne (à partir de la colonne de sauvegarde).
DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);
Une fois terminé, éteignez IDENTITY_INSERT
à nouveau.
SET IDENTITY_INSERT dbo.ident_test OFF;
Déposez la colonne temporaire que nous avons ajoutée:
ALTER TABLE dbo.ident_test DROP COLUMN id_temp;
Et enfin, réamorcez la IDENTITY
colonne, de sorte que l'enregistrement suivant id
reprendra après le nombre existant le plus élevé dans la id
colonne:
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
En vérifiant le tableau d'exemple, le id
nombre le plus élevé est 20.
SELECT * FROM dbo.ident_test;
Ajoutez une autre ligne et vérifiez sa nouvelle IDENTITY
:
INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;
Dans l'exemple, la nouvelle ligne aura id=21
. Enfin, si vous êtes satisfait, validez la transaction:
COMMIT TRANSACTION;
Important
Ce n'est pas une opération banale, et elle comporte plusieurs risques dont vous devez être conscient.
Faites-le dans un environnement de test dédié. Avoir des sauvegardes. :)
J'aime utiliser BEGIN/COMMIT TRANSACTION
car cela empêche d'autres processus de jouer avec la table pendant que vous êtes en train de la changer, et cela vous donne la possibilité de tout restaurer en cas de problème. Cependant, tout autre processus qui tente d'accéder à votre table avant d'avoir validé votre transaction finira par attendre. Cela peut être assez mauvais si vous avez une grande table et / ou si vous êtes dans un environnement de production.
OUTPUT .. INTO
ne fonctionnera pas si votre table cible a des contraintes de clé étrangère ou l'une des nombreuses autres fonctionnalités dont je ne me souviens pas du haut de ma tête. Vous pouvez à la place décharger les données dans une table temporaire, puis les réinsérer dans la table d'origine. Vous pourrez peut-être utiliser la commutation de partition (même si vous n'utilisez pas de partitions).
Exécutez ces instructions une par une, pas en tant que lot ou dans une procédure stockée.
Essayez de penser à d'autres choses qui peuvent dépendre de la id
colonne que vous supprimez et recréez. Tous les index devront être supprimés et recréés (comme nous l'avons fait avec la clé primaire). N'oubliez pas de scripter chaque index et contrainte que vous devrez recréer au préalable.
Désactivez les déclencheurs INSERT
et DELETE
sur la table.
Si la recréation de la table est une option:
Si la recréation de la table est une option pour vous, tout est beaucoup plus simple:
- Créez la table vide, avec la
id
colonne en tant que IDENTITY
,
- Set
IDENTITY_INSERT ON
pour la table,
- Remplissez la table,
- Set
IDENTITY_INSERT OFF
, et
- Ressuscitez l'identité.
IDENTITY
?