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 IDENTITY
columna y (2) asegurarse de que IDENTITY
comience 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 IDENTITY
columna que comenzará en 21 para el siguiente registro que se inserte. Para este ejemplo, la columna xyz
representa 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_temp
y configuremos esa columna a los id
valores 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 id
columna existente (no puede simplemente "agregar" una IDENTITY
a 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_INSERT
en la tabla, lo que significa que puede definir manualmente los valores de una IDENTITY
columna cuando inserta nuevas filas (sin embargo, no actualiza las filas existentes).
SET IDENTITY_INSERT dbo.ident_test ON;
Con ese conjunto, DELETE
todas las filas de la tabla, pero las filas que está eliminando están OUTPUT
en la misma tabla, pero con valores específicos para la id
columna (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_INSERT
apague 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 IDENTITY
columna, para que los siguientes registros id
se reanuden después del número más alto existente en la id
columna:
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
Verificando la tabla de ejemplo, el id
nú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 TRANSACTION
porque 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 .. INTO
no 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 id
columna 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 INSERT
y DELETE
disparadores 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
id
columna como un IDENTITY
,
- Poner
IDENTITY_INSERT ON
para la mesa,
- Poblar la mesa,
- Conjunto
IDENTITY_INSERT OFF
, y
- Reseed la identidad.
IDENTITY
?