Como lidar com as restrições do FK ao importar dados usando o Assistente para Importação / Exportação do DTS?

16

Estou tentando usar o Assistente para Importação e Exportação do SQL Server para copiar dados do meu banco de dados de produção para meu banco de dados de desenvolvimento, mas quando o faço falhar com o erro "A instrução INSERT entrou em conflito com a restrição FOREIGN KEY", tenho mais de 40 tabelas com lotes de restrições FK, existe alguma maneira fácil de lidar com isso sem ter que escrever um script de restrição / adição de constrat?

Edit: Acabei de descobrir que, na edição da Web do SQL Server, que é o que estou executando, o DTS não permitirá que você salve pacotes.


fonte

Respostas:

28

Foi-me dada esta solução no SQLTeam.com:

Usar:

 EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'

Importe seus dados

EXEC sp_msforeachtable 'ALTER TABLE ? CHECK CONSTRAINT all'

Usando esse método, consegui importar todos os dados sem problemas.

Paul White 9
fonte
1
sp_msforeachtable(e sp_MSForEachDb) não está documentado e não é suportado. Você não deve / evita usá-lo. Pode pular as mesas !! Consulte esta postagem em @AaronBertrand -> sqlblog.com/blogs/aaron_bertrand/archive/2010/12/29/… e este item de conexão - (MS indicando que não a corrigem) -> connect.microsoft.com/SQLServer / feedback / details / 264677 /…
Kin Shah
Funcionou perfeitamente para mim depois de horas batendo no cérebro tentando contornar as restrições do FK para uma exportação de dados.
levininja
Em execução no Azure SQL V12, recebo o erro "Não foi possível encontrar o procedimento armazenado 'sp_msforeachtable'."
Dai
Não funciona de qualquer maneira: /
Douglas Gaskell
Você é o homem que salva vidas
Can Şahin Bakır
5

Eu produzi uma cópia exata de um banco de dados na minha máquina a partir de um servidor que eu não controlava.

Sou um idiota , mas foi o que fiz:

  1. Criei o banco de dados a partir do meu script que estava no controle de origem (dica, dica!) Se você não tiver o script, sempre poderá gerá-lo a partir do banco de dados existente por meio da Tasksopção

  2. Se algum dado foi inserido automaticamente no YourDB na criação, execute a DELETE FROM YourDB.dbo.tblYourTable.

    • Você não pode truncar dados quando existem chaves estrangeiras, então você precisa usá-lo DELETE.
  3. Execute isso no servidor de destino: USE YourDB; EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all';

  4. Clique com o botão direito do mouse em YourDB in Object Explorer. Clique em Tasks->Import Data...

  5. As primeiras telas do assistente são auto-explicativas.

  6. Na Select Source Table and Viewstela do assistente, clique na caixa de seleção ao lado de todas as tabelas que você deseja copiar.

  7. Para cada linha (tabela) nessa tela, clique nela para que fique realçada e clique em Edit Mappings.

  8. Para cada linha (tabela), clique / verifique Append rows to the destination tablee Enable identity insert.

    • Se você clicar Delete rows in destination tablenele, falhará porque não emite um DELETEcomando, ele emite um TRUNCATEcomando que ainda entra em conflito com nossas chaves estrangeiras porque TRUNCATEnão é governado pelo NOCHECK CONSTRAINTanterior.
  9. Clique no restante do assistente e clique em Finish.

  10. Preste atenção nos erros ; provavelmente é bom ignorar avisos.

    • Se houver erros, clique no Reportbotão e visualize o relatório. Experimente e suss para fora o que era um Success, Errore Stopped. Você provavelmente precisará corrigir a causa raiz do erro que está oculto nesse relatório em algum lugar. Então, você provavelmente precisará fazer um DELETE FROM YourDB.dbo.theErrorTable. Agora clique no botão voltar no assistente de importação e desmarque todas as tabelas que eram a Success. Repita ad infinitum.
  11. Execute isso no servidor de destino: USE YourDB; EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all';

    • Se houver erros, ... eu não sei, mas corrija-os e tente novamente!
  12. Yay! :)

Obrigado a todos que responderam a essa pergunta e perguntas semelhantes a essa na rede SE por me ajudarem a descobrir isso.

Zach Mierzejewski
fonte
Você é um salva-vidas
Tom Gullen 16/03/16
1
Sério, muito obrigado, tinha um backup em uma unidade corrompida, não conseguia copiar o banco de dados em nenhum lugar (erro de E / S). Importar os dados algumas tabelas por vez dessa maneira me ajudou a recuperar 99% deles.
Tom Gullen
1
Você é demais! Outro comando que me ajudou: EXEC sp_msforeachtable 'delete from? '; Se ocorrer um erro, apague tudo é a lei. roteiro sp_msforeachtable está aqui gist.githubusercontent.com/metaskills/893599/raw/...
Sanchitos
4

No assistente de importação, você pode excluir as linhas primeiro e, se tiver campos de identidade, poderá ativar a inserção de identidade como abaixo

insira a descrição da imagem aqui

Se você deseja desativar a restrição de verificação, quando o assistente solicitar que você salve o pacote, salve-o e edite o gerenciador de conexões conforme abaixo:

insira a descrição da imagem aqui

Nota: Você não pode TRUNCAR a tabela quando houver chaves estrangeiras definidas.

Kin Shah
fonte
3

Não abandone as restrições.

O que você deve fazer é salvar o pacote SSIS que o assistente cria e depois editá-lo em BIDS / SSDT. Ao editar o pacote, você poderá controlar a ordem em que as tabelas são processadas para poder processar as tabelas pai e, em seguida, processar as tabelas filho quando todas as tabelas pai estiverem concluídas.

mrdenny
fonte
3
Isso também não é realmente eficaz, levaria quase uma hora agora para modificar o pacote para garantir que tudo esteja na ordem correta, e mesmo assim não posso ter certeza. Isso ficaria mais pesado à medida que o DB crescesse e, sempre que possível, não, obrigado. Tem que haver uma maneira simples de fazer isso.
1

Problemas como esse nos mostram que as pessoas que fabricam o SQL Server nunca realmente usaram seu produto. Essa é uma omissão tão flagrante que é preciso se perguntar o que mais eles simplesmente esqueceram de fazer corretamente (eu tenho uma lista de cerca de 30 outras questões enlouquecedoras como essa que eu tive que superar para fazer isso funcionar como outros DBs o fazem da caixa, incluindo o fato de que precisamos de um assistente ruim para fazer isso em primeiro lugar [se eu tivesse o tempo gasto esperando que esse assistente se conectasse e enumerasse as mesmas tabelas para o mesmo banco de dados, sempre ... eu teria tempo para umas boas férias]).

Sou muito preguiçoso e não quero digitar EXEC sp_msforeachtable ...duas vezes toda vez que faço isso. Minha solução foi deixar as restrições no servidor de produção e removê-las do servidor de desenvolvimento. Isso evitará o erro, mas esse método tem alguns efeitos colaterais MUITO GRANDES. Primeiro, você não poderá mais restaurar apenas um backup completo no servidor de desenvolvimento (a menos que você consiga removê-los novamente). Segundo, isso funciona melhor quando você tem certeza de que os consumidores de seus dados também impõem essas restrições (ou não se importam com elas). No meu caso, temos apenas um consumidor (nosso site) e, por isso, incorporamos essas restrições no código do site (ou seja, antes de excluir um registro de usuário, excluímos todos os registros telefônicos desse usuário primeiro). Sim, isso basicamente nega a necessidade de restrições em primeiro lugar e dobra o trabalho que eu preciso fazer, mas também me dá a chance de verificar se meu código funciona com ou sem restrições baseadas em DBMS (o fato é que elas ainda estão no produto servidor apenas como plano de contingência). Você pode chamar isso de falha no meu design, mas prefiro chamá-lo de solução alternativa para um DBMS defeituoso. De qualquer forma, ainda é mais rápido e fácil fazer isso em qualquer outro lugar do que no MSSQL, porque é incapaz de lidar com seu próprio design.

krowe2
fonte
0

Eu acho que você não pode executar backup e restauração do servidor de produção, pois são dados cruciais. Bem, sem os direitos adequados, ele realmente se torna mais complicado. Mas se você tiver o backup e restauração do db certo, poderá executá-lo.

Ou então, uma maneira que eu recomendaria é eliminar todas as restrições e índices e adicioná-los novamente depois que os dados forem importados ou exportados.

Não é uma resposta exata, mas será processada rapidamente.

user2404431
fonte
Obrigado, mas eu disse especificamente que não quero criar um script de restrição de criação / queda.
0

Basta ler esse tópico. É um post antigo, mas aqui está o que eu fiz para ajudar as futuras pessoas a lerem isso.

No meu caso, eu queria importar para uma tabela idêntica vazia. Ao editar o mapeamento, seleciono <ignore>a chave primária. Todo o meu conteúdo está sendo adicionado automaticamente com agrado.

Espero que ajude alguém

Greg
fonte
1
Ignorar a chave primária ajudaria com chaves estrangeiras?
Dezso
No meu caso, sim, porque eu estava realmente duplicando uma tabela. Então eu terminei com as mesmas chaves primárias. Portanto, as chaves estrangeiras que apontam para a minha tabela ainda correspondem à entrada correta
Greg