Como truncar uma tabela restrita de chave estrangeira?

648

Por que não faz um TRUNCATE no mygrouptrabalho? Mesmo que ON DELETE CASCADE SETeu recebo:

ERRO 1701 (42000): Não é possível truncar uma tabela referenciada em uma restrição de chave estrangeira ( mytest. instance, CONSTRAINT instance_ibfk_1FOREIGN KEY ( GroupID) REFERENCES mytest. mygroup( ID))

drop database mytest;
create database mytest;
use mytest;

CREATE TABLE mygroup (
   ID    INT NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE=InnoDB;

CREATE TABLE instance (
   ID           INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
   GroupID      INT NOT NULL,
   DateTime     DATETIME DEFAULT NULL,

   FOREIGN KEY  (GroupID) REFERENCES mygroup(ID) ON DELETE CASCADE,
   UNIQUE(GroupID)
) ENGINE=InnoDB;
user391986
fonte

Respostas:

1001

Você não pode TRUNCATEaplicar uma tabela com restrições de FK ( TRUNCATEnão é a mesma queDELETE ).

Para contornar isso, use uma dessas soluções. Ambos apresentam riscos de danificar a integridade dos dados.

Opção 1:

  1. Remover restrições
  2. Realizar TRUNCATE
  3. Exclua manualmente as linhas que agora têm referências a lugar nenhum
  4. Criar restrições

Opção 2: sugerida pelo usuário447951 na resposta

SET FOREIGN_KEY_CHECKS = 0; 
TRUNCATE table $table_name; 
SET FOREIGN_KEY_CHECKS = 1;
zerkms
fonte
46
@barjonah: na verdade, isso pode prejudicar a integridade dos dados (consulte stackoverflow.com/questions/5452760/… ). Portanto, o que você chama de "luz" no mundo real é considerado uma má prática. PS: obrigado pelo
voto negativo
1
Aqui está uma maneira muito boa de encontrar chaves estrangeiras órfãs (restaurar a integridade dos dados) http://stackoverflow.com/a/12085689/997776
SandorRacz
desativar chave estrangeira antes de truncar também é uma boa maneira, eu fiz isso com sucesso da fonte: stackoverflow.com/questions/8641703/…
Dung
2
@Dung desabilitar verificações de chave estrangeira é permitido apenas no período de desenvolvimento. Ele quebra todos os relacionamentos existentes. zerkms está 100% certo quanto à integridade dos dados. Você pode verificação de chaves estrangeiras não desativar em um banco de dados de trabalho a menos que você está planejando para esvaziá-lo completamente (ou pelo menos todas as tabelas relacionadas)
NoobishPro
1
@ Kamlesh não é a minha solução, aconselho a não fazê-lo dessa maneira bárbara.
zerkms
1308

Sim você pode:

SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE table1;
TRUNCATE table2;

SET FOREIGN_KEY_CHECKS = 1;

Com essas instruções, você corre o risco de inserir linhas em suas tabelas que não aderem às FOREIGN KEYrestrições.

user447951
fonte
30
precisamos definir SET FOREIGN_KEY_CHECKS = 1; novamente depois?
vinc3m1
77
Não você não. A configuração é válida apenas durante a conexão. Assim que você se desconectar, a próxima conexão voltará a ser 1.
The Pellmeister
7
Isso não aplica o evento 'ON DELETE' na tabela referenciada, portanto, essa não é uma resposta completa.
Omer Sabic
5
Se estiver usando no PHPMYADMIN, isso funcionará apenas se você usar todas as transações na mesma janela SQL (separadas por a ;). Isso ocorre porque cada chamada SQL web fresco irá repor o FOREIGN_KEY_CHECKSpara 1.
Sablefoste
1
Aqui está uma maneira muito boa para encontrar as chaves estrangeiras órfãs (restaurar a integridade dos dados) em caso você esteja interessado http://stackoverflow.com/a/12085689/997776
SandorRacz
173

Eu simplesmente faria isso com:

DELETE FROM mytest.instance;
ALTER TABLE mytest.instance AUTO_INCREMENT = 1;
George Garchagudashvili
fonte
5
Inteligente. Quando você deseja excluir todos os registros de qualquer maneira, é possível redefinir o incremento automático.
Winkbrace
6
Esta é obviamente a melhor maneira de fazê-lo. Não há risco de perder restrições, basta excluir. Vale a pena notar que o DELETEdesempenho é mais lento que TRUNCATE. Mas como essa ação geralmente é executada apenas raramente, isso não importa.
phil294
Isso é bom se é tudo o que você deseja fazer, mas DELETEpode ser absolutamente brutal se você tiver muitas linhas - uma vez que atinge os logs, enquanto TRUNCATEapenas retira os dados. Realmente depende do caso de uso.
Jeff
1
quando estou usando a instrução delete, ele informa o erro 1175: Você está usando o modo de atualização segura, basta adicionar SET SQL_SAFE_UPDATES = 0; então está tudo bem
tyan
Ao usar esta solução, ela reporta a error 1175: You are using safe update mode,...cláusula change delete para DELETE FROM mydb.mytable where id != 0torná-la perfeita.
Shihe Zhang 17/07/2018
17

você pode fazer

DELETE FROM `mytable` WHERE `id` > 0
Ali Sadran
fonte
1
Eu tentei-bur, o seguinte erro apareceu: Código de erro: 1142. comando DELETE negado para o usuário 'root' @ 'localhost' para a tabela 'mytable'
AAEM
ou apenas DELETE FROMmytable
Miloslav Milo Janoušek
Isso não redefiniria o incremento automático.
vivek_23 19/09/19
13

Conforme documentação do mysql , TRUNCATE não pode ser usado em tabelas com relacionamentos de chave estrangeira. Não há AFAIK alternativo completo.

A eliminação do contraint ainda não chama ON DELETE e ON UPDATE. A única solução em que posso pensar em ATM é:

  • excluir todas as linhas, soltar as chaves estrangeiras, truncar, recriar chaves
  • excluir todas as linhas, redefinir incremento automático (se usado)

Parece que TRUNCATE no MySQL ainda não é um recurso completo (também não invoca gatilhos). Ver comentário

Omer Sabic
fonte
7
Uma observação sobre o seu ponto de vista de que o MySQL está TRUNCATEincompleto - truncado não deve chamar gatilhos, etc. Se assim fosse, seria o mesmo que DELETE! É independente de linha, portanto, é incapaz de executar operações relacionadas à linha (como invocar gatilhos ou examinar chaves estrangeiras). Funciona da mesma maneira no Oracle e no Sql Server .
Simon MᶜKenzie
8

Fácil se você estiver usando o phpMyAdmin.

Basta desmarcar a Enable foreign key checksopção na SQLguia e executarTRUNCATE <TABLE_NAME>

insira a descrição da imagem aqui

Ajmal Salim
fonte
8

Enquanto essa pergunta foi feita, eu não sabia, mas agora, se você usa o phpMyAdmin, pode simplesmente abrir o banco de dados e selecionar a (s) tabela (s) que deseja truncar.

  • Na parte inferior, há uma lista suspensa com muitas opções. Abra-o e selecione a Emptyopção sob o cabeçalho Delete data or table.
  • Leva você para a próxima página automaticamente, onde há uma opção na caixa de seleção chamada Enable foreign key checks. Basta desmarcar e pressionar o Yesbotão e as tabelas selecionadas serão truncadas.

Talvez ele execute internamente a consulta sugerida na resposta do usuário447951 , mas é muito conveniente usar a partir da interface do phpMyAdmin.

Rolen Koh
fonte
7

Testado no banco de dados MYSQL

Solução 1:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;

Solução 2:

DELETE FROM table1;
ALTER TABLE table1 AUTO_INCREMENT = 1;
TRUNCATE table1;

Isso funciona para mim. Espero que isso ajude você também. Obrigado por fazer esta pergunta.

Kamlesh
fonte
6

A resposta é realmente a fornecida por zerkms , como indicado na Opção 1 :

Opção 1 : que não corre o risco de danificar a integridade dos dados:

  1. Remover restrições
  2. Executar TRUNCATE
  3. Exclua manualmente as linhas que agora têm referências a lugar nenhum
  4. Criar restrições

A parte complicada é remover restrições , por isso, quero lhe dizer como, caso alguém precise saber como fazer isso:

  1. Execute a SHOW CREATE TABLE <Table Name>consulta para ver qual é o nome da sua FOREIGN KEY (quadro vermelho na imagem abaixo):

    insira a descrição da imagem aqui

  2. Corra ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>. Isso removerá a restrição de chave estrangeira.

  3. Solte o índice associado (na página de estrutura da tabela) e pronto.

recriar chaves estrangeiras:

ALTER TABLE <Table Name>
ADD FOREIGN KEY (<Field Name>) REFERENCES <Foreign Table Name>(<Field Name>);
Pmpr
fonte
3

Basta usar CASCADE

TRUNCATE "products" RESTART IDENTITY CASCADE;

Mas esteja pronto para exclusões em cascata)

Alexus1024
fonte
3
O OP adicionou aos itens MySQL. Embora isso seja válido no Postgres, está incorreto no MySQL.
Peter
1

Se o mecanismo de banco de dados para tabelas for diferente, você receberá esse erro, então altere-os para InnoDB

ALTER TABLE my_table ENGINE = InnoDB;
sajad abbasi
fonte
0

Obter o antigo estado de verificação de chave estrangeira e o modo sql é a melhor maneira de truncar / soltar a tabela como o Mysql Workbench faz ao sincronizar o modelo com o banco de dados.

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;`
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

DROP TABLE TABLE_NAME;
TRUNCATE TABLE_NAME;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Vijay Arun
fonte