Criei uma tabela em um banco de dados que já existe em outro banco de dados. Foi preenchido inicialmente com os dados antigos do banco de dados. A PK da tabela precisava receber os valores que já existem nesses registros, para que não pudessem ser incrementados automaticamente.
Agora preciso que a nova tabela tenha seu PK como incremento automático. Mas como posso fazer isso depois que o PK já existir e tiver dados?
IDENTITY
?Respostas:
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 oIDENTITY
início do valor mais recente nas linhas existentes.Primeiro, alguns dados de teste para jogar:
O objetivo é criar a coluna de chave primária da tabela
id
, umaIDENTITY
coluna que começará às 21 para o próximo registro que será inserido. Neste exemplo, a colunaxyz
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:
Agora, vamos adicionar uma coluna de trabalho temporária
id_temp
e definir essa coluna com osid
valores da coluna existente :Em seguida, precisamos soltar a
id
coluna existente (você não pode simplesmente "adicionar" umIDENTITY
a uma coluna existente, é necessário criar a coluna como umIDENTITY
). A chave primária também tem que ir, porque a coluna depende dela.... e adicione a coluna novamente, desta vez como uma
IDENTITY
, junto com a chave primária:Aqui é onde fica interessante. Você pode ativar
IDENTITY_INSERT
a tabela, o que significa que você pode definir manualmente os valores de umaIDENTITY
coluna ao inserir novas linhas (embora não atualize as linhas existentes).Com esse conjunto,
DELETE
todas as linhas da tabela, mas as linhas que você está excluindo, estãoOUTPUT
diretamente na mesma tabela - mas com valores específicos para aid
coluna (na coluna de backup).Feito isso, desligue
IDENTITY_INSERT
novamente.Solte a coluna temporária que adicionamos:
E, finalmente, redefina a
IDENTITY
coluna, para que os próximos registrosid
sejam retomados após o maior número existente naid
coluna:Verificando a tabela de exemplo, o
id
número mais alto é 20.Adicione outra linha e verifique a nova
IDENTITY
:No exemplo, a nova linha terá
id=21
. Por fim, se você estiver feliz, confirme a transação: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
eDELETE
gatilhos na mesa.Se recriar a tabela for uma opção:
Se recriar a tabela é uma opção para você, tudo é muito mais simples:
id
coluna comoIDENTITY
,IDENTITY_INSERT ON
para a mesa,IDENTITY_INSERT OFF
efonte
IDENTITY_INSERT ON
, preenchê-lo e desativá-lo. Era isso que eu queria fazer, mas não sabia que o MSSQL o suportava.O uso de UPDATE, DELETE ou INSERT para mover dados pode levar bastante tempo e usar recursos (IO) nos arquivos / discos de dados e de log. É possível evitar o preenchimento do log de transações com potencialmente muitos registros enquanto trabalha em uma tabela grande: Usando a alternância de partições, apenas os metadados são alterados.
Não há movimentação de dados envolvidos e, portanto, isso é realizado muito rapidamente (quase instantaneamente).
Tabela de amostra
A pergunta não mostra a tabela original DDL. O seguinte DDL será usado como exemplo nesta resposta:
Meia dúzia de IDs aleatórios fictícios de 0 a 15 são adicionados a esta consulta:
Dados de exemplo em
IdT
Nova tabela com
IDENTITY(0, 1)
O único problema
idT
é com a falta daIDENTITY(0, 1)
propriedade no id. Uma nova tabela com uma estrutura semelhante eIDENTITY(0, 1)
é criada:Além de
IDENTITY(0, 1)
,idT_Switch
é idêntico aidT
.Chaves estrangeiras
As chaves estrangeiras ativadas
idT
devem ser removidas para permitir que essa técnica seja usada.Interruptor de Partição
As tabelas
idT
eidT_Switch
têm uma estrutura compatível. Em vez de usarDELETE
,UPDATE
eINSERT
declarações para mover as linhas deidT
aidT_Switch
ou emidT
si mesmo,ALTER TABLE ... SWITCH
pode ser usado:A única 'partição' de
PK_idT
(a tabela inteira) é movida paraPK_idT_Switch
(e vice-versa).idT
agora contém 0 linhas eidT_Switch
contém 6 linhas.Você pode encontrar a lista completa dos requisitos de compatibilidade de origem e destino aqui:
Transferindo dados com eficiência usando a alternância de partições
Observe que esse uso de
SWITCH
não requer Enterprise Edition, porque não há particionamento explícito. Uma tabela não particionada é considerada uma tabela com uma única partição do SQL Server 2005 em diante.Substituir
idT
idT
agora está vazio e inútil e pode ser descartado:idT_Switch
pode ser renomeado e substituirá aidT
tabela antiga :Chaves estrangeiras
Chaves estrangeiras podem ser adicionadas novamente à nova
idT
tabela. Qualquer outra coisa removida anteriormenteidT
para tornar as tabelas compatíveis para alternar também precisará ser refeita.Reseed
Este comando retorna 0. A tabela idT contém 6 linhas com MAX (id) = 15. DBCC CHECKIDENT (table_name) pode ser usado:
Como 15 é maior que 0, ele será propagado novamente automaticamente sem procurar MAX (id):
IDENT_CURRENT agora retorna 15 .
Teste e adicione dados
Uma
INSERT
declaração simples :Adiciona esta linha:
A
id
coluna agora está usando a identidade e o valor recém-inserido é realmente 16 (15 + 1).Mais Informações
Há uma pergunta e resposta relacionadas com mais informações sobre a
SWITCH
técnica aqui:Por que a remoção da propriedade Identity em uma coluna não é suportada
fonte
Se você deseja começar com um novo valor de identidade, precisará reenviar sua identidade. Veja a documentação para
CHECKIDENT
fonte
ENABLE e DISABLE IDENTITY_INSERT
Se sua tabela for TABLE_A, então
fonte