A maneira como entendo sua pergunta é que você tem uma tabela existente com uma coluna que até agora foi preenchida com valores manuais e agora deseja (1) tornar essa coluna uma IDENTITY
coluna e (2) garantir que o IDENTITY
início do valor mais recente nas linhas existentes.
Primeiro, alguns dados de teste para jogar:
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');
O objetivo é criar a coluna de chave primária da tabela id
, uma IDENTITY
coluna que começará às 21 para o próximo registro que será inserido. Neste exemplo, a coluna xyz
representa todas as outras colunas da tabela.
Antes de fazer qualquer coisa, leia os avisos na parte inferior desta postagem.
Primeiro, caso algo dê errado:
BEGIN TRANSACTION;
Agora, vamos adicionar uma coluna de trabalho temporária id_temp
e definir essa coluna com os id
valores da coluna existente :
ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;
Em seguida, precisamos soltar a id
coluna existente (você não pode simplesmente "adicionar" um IDENTITY
a uma coluna existente, é necessário criar a coluna como um IDENTITY
). A chave primária também tem que ir, porque a coluna depende dela.
ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;
... e adicione a coluna novamente, desta vez como uma IDENTITY
, junto com a chave primária:
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);
Aqui é onde fica interessante. Você pode ativar IDENTITY_INSERT
a tabela, o que significa que você pode definir manualmente os valores de uma IDENTITY
coluna ao inserir novas linhas (embora não atualize as linhas existentes).
SET IDENTITY_INSERT dbo.ident_test ON;
Com esse conjunto, DELETE
todas as linhas da tabela, mas as linhas que você está excluindo, estão OUTPUT
diretamente na mesma tabela - mas com valores específicos para a id
coluna (na coluna de backup).
DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);
Feito isso, desligue IDENTITY_INSERT
novamente.
SET IDENTITY_INSERT dbo.ident_test OFF;
Solte a coluna temporária que adicionamos:
ALTER TABLE dbo.ident_test DROP COLUMN id_temp;
E, finalmente, redefina a IDENTITY
coluna, para que os próximos registros id
sejam retomados após o maior número existente na id
coluna:
DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)
Verificando a tabela de exemplo, o id
número mais alto é 20.
SELECT * FROM dbo.ident_test;
Adicione outra linha e verifique a nova IDENTITY
:
INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;
No exemplo, a nova linha terá id=21
. Por fim, se você estiver feliz, confirme a transação:
COMMIT TRANSACTION;
Importante
Esta não é uma operação trivial e traz muitos riscos dos quais você deve estar ciente.
Faça isso em um ambiente de teste dedicado. Tenha backups. :)
Eu gosto de usar BEGIN/COMMIT TRANSACTION
porque evita que outros processos mexam com a tabela enquanto você está no meio da alteração e oferece a possibilidade de reverter tudo se algo der errado. No entanto, qualquer outro processo que tente acessar sua tabela antes de você confirmar sua transação acabará aguardando. Isso pode ser muito ruim se você tiver uma tabela grande e / ou estiver em um ambiente de produção.
OUTPUT .. INTO
não funcionará se sua tabela de destino tiver restrições de chave estrangeira ou qualquer um de vários outros recursos que não me lembro de nada. Em vez disso, você pode descarregar os dados em uma tabela temporária e depois inseri-los novamente na tabela original. Você poderá usar a alternância de partições (mesmo que não use partições).
Execute essas instruções uma por uma, não como um lote ou em um procedimento armazenado.
Tente pensar em outras coisas que podem depender da id
coluna que você está soltando e recriando. Quaisquer índices terão que ser eliminados e recriados (como fizemos com a chave primária). Lembre-se de criar um script para todos os índices e restrições que você precisará recriar antes.
Desative any INSERT
e DELETE
gatilhos na mesa.
Se recriar a tabela for uma opção:
Se recriar a tabela é uma opção para você, tudo é muito mais simples:
- Crie a tabela vazia, com a
id
coluna como IDENTITY
,
- Conjunto
IDENTITY_INSERT ON
para a mesa,
- Preencher a tabela,
- Definir
IDENTITY_INSERT OFF
e
- Reseed a identidade.
IDENTITY
?