Eu tenho um projeto SQL Server Data Tools (VS2012) que é publicado automaticamente durante o processo de compilação. Uma coluna foi atualizada recentemente de um int
para decimal(18,4)
. Como resultado dessa alteração, a publicação falha com o erro
(49,1): SQL72014: .Net SqlClient Data Provider: Msg 50000, Level 16, State 127, Line 6 Linhas foram detectadas. A atualização do esquema está terminando porque pode ocorrer perda de dados. (44,0): SQL72045: Erro de execução de script. O script executado: /* O tipo da coluna QuantidadeRecebida na tabela [dbo].[Reconciliação_Recebimento] atualmente é INT NOT NULL, mas está sendo alterado para DECIMAL (18, 4) NOT NULL. Pode ocorrer perda de dados. */
IF EXISTS (selecione top 1 1 de [dbo].[Reconciliation_Receiving]) RAISERROR (N'Rows foram detectadas. A atualização do esquema está terminando porque pode ocorrer perda de dados.', 16, 127) WITH NOWAIT Ocorreu um erro enquanto o lote estava sendo sendo executado.
Entendo por que estou recebendo esse erro e sei que ele pode ser resolvido desativando o sinalizador "Bloquear implantação incremental se ocorrer perda de dados". No entanto, há uma forte oposição à desabilitação desse recurso, portanto, não será uma solução aceitável.
A única outra solução que consigo pensar é fazer o seguinte:
- Faça uma tabela temporária e copie o conteúdo da tabela existente na tabela temporária
- Truncar a tabela existente
- Deixe o SSDT atualizar o tipo de dados
- Preencha os dados de volta da tabela temporária
Isso parece terrivelmente desajeitado e ineficiente, no entanto.
Existe uma alternativa melhor?
Fiquei tentado a ignorar essa bandeira também, mas fiquei do lado de seus colegas de trabalho e agora tento lidar com essas questões "corretamente". A rota (marginalmente) menos complicada é usar scripts de pré e pós-implantação para fazer o trabalho com uma renomeação.
Dependendo da natureza do destino, você pode precisar cuidar de descartar e recriar restrições de chave estrangeira.
No meu caso eu estava removendo uma coluna de uma tabela.
A solução fornecida nesta resposta não funcionou para mim, resultou em um
invalid object name
erro durante a publicação.Descobri que era necessário copiar as linhas da tabela, desabilitar a verificação de restrição e excluir as linhas em um script de pré-implantação e, em seguida, copiar as linhas de volta para a tabela com a inserção de identidade habilitada no script pós-implantação.
Em Script.PreDeployment.sql:
Em Script.PostDeployment.sql
ALTER TABLE tabela_1 ALTER COLUMN [a] decimal (18,2)
Fará o trabalho neste caso, solução muito mais simples para um script de pré-implantação. Também descobri que alterar o destino antes da publicação evitará que o erro de perda de dados seja gerado.
Às vezes, o SSDT identificará soluções ALTER TABLE/ALTER COLUMN e as usará na compilação, mas não conheço as regras para tornar isso confiável da perspectiva do usuário. Não sei porque não usa nesse caso. Não há chance de perda de dados com ALTER COLUMN.