Falha na restrição de chave estrangeira falsa

110

Recebo esta mensagem de erro:

ERROR 1217 (23000) na linha 40: Não é possível excluir ou atualizar uma linha pai: uma restrição de chave estrangeira falha

... quando tento derrubar uma mesa:

DROP TABLE IF EXISTS `area`;

... definido assim:

CREATE TABLE `area` (
  `area_id` char(3) COLLATE utf8_spanish_ci NOT NULL,
  `nombre_area` varchar(30) COLLATE utf8_spanish_ci NOT NULL,
  `descripcion_area` varchar(100) COLLATE utf8_spanish_ci NOT NULL,
  PRIMARY KEY (`area_id`),
  UNIQUE KEY `nombre_area_UNIQUE` (`nombre_area`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

O engraçado é que eu já eliminei todas as outras tabelas do esquema que possuem chaves estrangeiras area. Na verdade, o banco de dados está vazio, exceto pela areatabela.

Como pode haver linhas filho se não houver nenhum outro objeto no banco de dados? Pelo que eu sei, o InnoDB não permite chaves estrangeiras em outros esquemas, permite?

(Posso até executar um RENAME TABLE area TO something_elsecomando: -?)

Álvaro González
fonte
É possível que a tabela seja parte de um relacionamento de integridade referencial em outro esquema?
Raj More
Tenho algumas outras cópias do aplicativo, então é sempre possível. No entanto, a sintaxe que uso é basicamente CONSTRAINT fk_servicio_area1 FOREIGN KEY (area_id) REFERENCES area (area_id), ou seja, nenhum nome de esquema na referência de tabela: -?
Álvaro González

Respostas:

101

Duas possibilidades:

  1. Existe uma tabela dentro de outro esquema ("banco de dados" na terminologia mysql) que tem uma referência FK
  2. O dicionário de dados interno innodb está fora de sincronia com o mysql.

Você pode ver qual tabela era (uma delas, pelo menos) fazendo um "MOSTRAR STATUS DO ENGINE INNODB" depois que o drop falhar.

Se for o último caso, descartarei e restaurarei todo o servidor, se possível.

O MySQL 5.1 e superior fornecerão o nome da tabela com o FK na mensagem de erro.

MarkR
fonte
1
Não consigo mais reproduzir o problema. O dicionário fora de sincronia se destaca como um motivo provável. Vou testá-lo dia e ver quais SHOW ENGINE INNODB STATUSrelatórios.
Álvaro González
3
Obrigado por esta resposta! Eu tinha uma tabela muitos para muitos ainda referenciando a tabela que não poderíamos remover, então eu tive que remover essa tabela primeiro.
Christian Oudard
5
SHOW ENGINE INNODB STATUS lista o último erro de chave estrangeira em "LATEST FOREIGN KEY ERROR". Isso tem um carimbo de data / hora.
bbrame
pode haver uma tabela ainda com uma chave de referência para a tabela de assunto. foi no meu caso, assim.
RT
Economizei muito tempo. Caiu o banco de dados em "
LATEST
121

Sob demanda, agora como uma resposta ...

Ao usar o MySQL Query Browser ou phpMyAdmin, parece que uma nova conexão é aberta para cada consulta ( bugs.mysql.com/bug.php?id=8280 ), tornando necessário escrever todas as instruções drop em uma consulta, por exemplo.

SET FOREIGN_KEY_CHECKS=0; 
DROP TABLE my_first_table_to_drop; 
DROP TABLE my_second_table_to_drop; 
SET FOREIGN_KEY_CHECKS=1; 

Onde o SET FOREIGN_KEY_CHECKS=1serve como medida de segurança extra ...

Karlis Rode
fonte
2
Para aqueles que estão criando um dump usando phpMyAdmin, existe uma opção "Desativar verificações de chave estrangeira" que será adicionada automaticamente SET FOREIGN_KEY_CHECKS=0;ao início do dump.
Mike
Parece que o phpMyAdmin implementou esse recurso adorável, agora estou esperando o mysqlWorkbench fazer o mesmo! :)
Karlis Rode
@CodeMed Para sua informação, aceitei a resposta do MarkR porque ela fornece uma explicação para o problema que faz sentido - embora eu admita que não pude verificar, já que não enfrentei o mesmo problema nos 6 anos seguintes, nem mesmo uma vez. Esta e as respostas anteriores fornecem uma solução alternativa (ótimo para esse bem), mas não respondem realmente à pergunta em si e, como você só pode aceitar uma resposta, tive que escolher.
Álvaro González
1
Aviso: esta não é uma solução, mas apenas uma solução alternativa para o homem preguiçoso. Depois de usar isso (com registros em algumas outras tabelas apontando para a tabela eliminada), você experimentará chaves estrangeiras penduradas que fatalmente quebram a consistência (o C no ACID ) de seu banco de dados e seus aplicativos começarão a lançar exceções em todo o lugar. Voce foi avisado.
bekce
Embora eu tenha certeza de que o aviso de bekce deve ser compreendido e atendido, essa solução funcionou para mim, em uma situação em que eu estava confiante de que também estava descartando todas as tabelas que apontavam para as tabelas com as restrições de chave estrangeira problemáticas.
user1147171
47

Desativar verificação de chave estrangeira

SET FOREIGN_KEY_CHECKS=0
Flakron Bytyqi
fonte
62
O comando correto parece ser SET FOREIGN_KEY_CHECKS=0e corrige a mensagem de erro. Você tem alguma ideia de por que isso é necessário? As chaves estrangeiras são armazenadas em cache mesmo depois que as tabelas desaparecem?
Álvaro González
1
Bem, para dizer a verdade, não tenho ideia de por que esse problema surge, mas certifique-se de desabilitar a verificação de chave toda vez que fizer grandes mudanças ou atualizações. Já aconteceu comigo várias vezes, deixando-me sem dormir por dias.
Flakron Bytyqi
55
Certifique-se de fazer isso SET FOREIGN_KEY_CHECKS=1;depois de terminar!
pedro_sland
5
Ao usar o MySQL Query Browser ou phpMyAdmin, parece que uma nova conexão é aberta para cada consulta ( bugs.mysql.com/bug.php?id=8280 ), tornando necessário escrever todas as instruções drop em uma consulta, por exemplo. SET FOREIGN_KEY_CHECKS=0; DROP TABLE my_first_table_to_drop; DROP TABLE my_second_table_to_drop; SET FOREIGN_KEY_CHECKS=1; Onde SET FOREIGN_KEY_CHECKS = 1 serve como uma medida de segurança extra ...
Karlis Rode
1
@KarlisRode, Bravo pelo comentário sobre phpMyAdmin. Se você colocasse isso como uma resposta, eu marcaria com +1.
Sablefoste
28

a partir deste blog :

Você pode desativar temporariamente as verificações de chave estrangeira:

SET FOREIGN_KEY_CHECKS=0;

Apenas certifique-se de restaurá-los quando terminar de mexer:

SET FOREIGN_KEY_CHECKS=1;
JackD
fonte
Boa resposta, pois eu estava desenvolvendo no local :)
Adelin
É uma solução alternativa válida (posso confirmar que funciona), mas a entrada do blog vinculado realmente não fala sobre o cenário nesta questão (um banco de dados que já está vazio, salvo para uma tabela).
Álvaro González
6

espero que seja o trabalho

SET Foreign_key_checks = 0; DROP TABLE table name; SET Foreign_key_checks = 1;

M_ Fa
fonte
Sim, funciona, como as várias vezes que já foi mencionado ;-)
Álvaro González
1

No Rails, pode-se fazer o seguinte usando rails console:

connection = ActiveRecord::Base.connection
connection.execute("SET FOREIGN_KEY_CHECKS=0;")
yeyo
fonte
0

Talvez você tenha recebido um erro ao trabalhar com esta tabela antes. Você pode renomear a tabela e tentar removê-la novamente.

ALTER TABLE `area` RENAME TO `area2`;
DROP TABLE IF EXISTS `area2`;
Vadim Pluzhinsky
fonte
0

Eu encontrei uma solução fácil, exporte o banco de dados, edite o que você deseja editar em um editor de texto, depois importe. Feito

Abdulrahman K
fonte
4
Essa é uma solução interessante, que provavelmente não deveria acontecer. Em vez disso, tudo o que precisa ser alterado deve ser feito por meio do DBMS. Editar um despejo de banco de dados em um editor de texto parece um caminho maduro para problemas.
Brandon Anzaldi
1
Eu realmente não entendo o que você gosta. Despejar o banco de dados, remover o CREATE TABLEcódigo e carregar o dump novamente ... não fará com que o MySQL remova a tabela. E se você quer dizer restaurar o dump em um novo banco de dados ... Se você quiser apagar todas as tabelas como eu, um banco de dados recém-criado já estará vazio. Se você quiser manter algumas tabelas, a SET FOREIGN_KEY_CHECKS=0solução alternativa mencionada em todos os lugares aqui funciona bem e é mais simples; e você provavelmente não precisa editar o dump, pois a nova cópia de seus dados possivelmente não terá um dicionário de dados fora de sincronia.
Álvaro González
-1

Não é possível excluir ou atualizar uma linha pai: uma restrição de chave estrangeira falha ( table1. user_role, CONSTRAINT FK143BF46A8dsfsfds@#5A6BD60FOREIGN KEY ( user_id) REFERENCES user( id))

O que fiz em duas etapas simples. primeiro eu deleto a linha filha na tabela filha, como

mysql> delete from table2 onde role_id = 2 && user_id = 20;

Consulta OK, 1 linha afetada (0,10 seg)

e a segunda etapa como excluir o pai

excluir da tabela1 onde id = 20;

Consulta OK, 1 linha afetada (0,12 s)

Com isso eu resolvo o problema, o que significa excluir filho e depois excluir pai

Espero que você tenha entendido. :)

Aadil Masavir
fonte
Por favor, leia a pergunta novamente. Você não pode remover uma tabela que não existe.
Álvaro González
neste cenário, podemos remover a restrição de chave estrangeira e, em seguida, tentar excluir a tabela. podemos soltar uma chave estrangeira como esta ALTER TABLE <TABLE_NAME> DROP CONSTRAINT <FOREIGN_KEY_NAME>
Aadil Masavir