La forma en que entiendo su pregunta es que tiene una tabla existente con una columna que hasta ahora se ha rellenado con valores manuales, y ahora desea (1) hacer que esta columna sea una IDENTITYcolumna y (2) asegurarse de que IDENTITYcomience desde el valor más reciente en las filas existentes.
En primer lugar, algunos datos de prueba para jugar:
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');
El objetivo es crear la columna de clave principal de la tabla id, una IDENTITYcolumna que comenzará en 21 para el siguiente registro que se inserte. Para este ejemplo, la columna xyzrepresenta todas las otras columnas de la tabla.
Antes de hacer nada, lea las advertencias al final de esta publicación.
En primer lugar, en caso de que algo salga mal:
BEGIN TRANSACTION;
Ahora, agreguemos una columna de trabajo temporal id_tempy configuremos esa columna a los idvalores de la columna existente :
ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;
A continuación, debemos descartar la idcolumna existente (no puede simplemente "agregar" una IDENTITYa una columna existente, debe crear la columna como una IDENTITY). La clave principal también tiene que ir, porque la columna depende de ella.
ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;
... y agregue la columna nuevamente, esta vez como IDENTITY, junto con la clave principal:
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);
Aquí es donde se pone interesante. Puede habilitar IDENTITY_INSERTen la tabla, lo que significa que puede definir manualmente los valores de una IDENTITYcolumna cuando inserta nuevas filas (sin embargo, no actualiza las filas existentes).
SET IDENTITY_INSERT dbo.ident_test ON;
Con ese conjunto, DELETEtodas las filas de la tabla, pero las filas que está eliminando están OUTPUTen la misma tabla, pero con valores específicos para la idcolumna (de la columna de copia de seguridad).
DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);
Una vez hecho, IDENTITY_INSERTapague nuevamente.
SET IDENTITY_INSERT dbo.ident_test OFF;
Suelte la columna temporal que agregamos:
ALTER TABLE dbo.ident_test DROP COLUMN id_temp;
Y finalmente, vuelva a colocar la IDENTITYcolumna, para que los siguientes registros idse reanuden después del número más alto existente en la idcolumna:
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
Verificando la tabla de ejemplo, el idnúmero más alto es 20.
SELECT * FROM dbo.ident_test;
Agregue otra fila y verifique su nuevo IDENTITY:
INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;
En el ejemplo, la nueva fila tendrá id=21. Finalmente, si estás contento, confirma la transacción:
COMMIT TRANSACTION;
Importante
Esta no es una operación trivial, y conlleva bastantes riesgos que debe tener en cuenta.
Haga esto en un entorno de prueba dedicado. Tener copias de seguridad. :)
Me gusta usarlo BEGIN/COMMIT TRANSACTIONporque evita que otros procesos se enreden con la tabla mientras estás en medio de cambiarla, y te da la posibilidad de deshacer todo si algo sale mal. Sin embargo, cualquier otro proceso que intente acceder a su tabla antes de que haya confirmado su transacción terminará esperando. Esto puede ser bastante malo si tiene una mesa grande y / o está en un entorno de producción.
OUTPUT .. INTOno funcionará si su tabla de destino tiene restricciones de clave externa o cualquiera de una serie de otras características que no puedo recordar en la parte superior de mi cabeza. En su lugar, puede descargar los datos en una tabla temporal y luego volver a insertarlos en la tabla original. Es posible que pueda usar el cambio de partición (incluso si no usa particiones).
Ejecute estas declaraciones una por una, no como un lote o en un procedimiento almacenado.
Intente pensar en otras cosas que pueden depender de la idcolumna que está soltando y volviendo a crear. Cualquier índice tendrá que descartarse y volver a crearse (como hicimos con la clave primaria). Recuerde escribir cada índice y restricción que necesitará recrear de antemano.
Deshabilita cualquiera INSERTy DELETEdisparadores en la mesa.
Si volver a crear la tabla es una opción:
Si volver a crear la tabla es una opción para usted, todo es mucho más simple:
- Cree la tabla vacía, con la
idcolumna como un IDENTITY,
- Poner
IDENTITY_INSERT ONpara la mesa,
- Poblar la mesa,
- Conjunto
IDENTITY_INSERT OFF, y
- Reseed la identidad.
IDENTITY?