Não é possível excluir ou atualizar uma linha pai: uma restrição de chave estrangeira falha

170

Ao fazer:

DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1 

Erros:

#1451 - Cannot delete or update a parent row: a foreign key constraint fails 
(paymesomething.advertisers, CONSTRAINT advertisers_ibfk_1 FOREIGN KEY 
(advertiser_id) REFERENCES jobs (advertiser_id))

Aqui estão as minhas tabelas:

CREATE TABLE IF NOT EXISTS `advertisers` (
  `advertiser_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` char(32) NOT NULL,
  `email` varchar(128) NOT NULL,
  `address` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `fax` varchar(255) NOT NULL,
  `session_token` char(30) NOT NULL,
  PRIMARY KEY (`advertiser_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `advertisers` (`advertiser_id`, `name`, `password`, `email`, `address`, `phone`, `fax`, `session_token`) VALUES
(1, 'TEST COMPANY', '', '', '', '', '', '');

CREATE TABLE IF NOT EXISTS `jobs` (
  `job_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `advertiser_id` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  `shortdesc` varchar(255) NOT NULL,
  `longdesc` text NOT NULL,
  `address` varchar(255) NOT NULL,
  `time_added` int(11) NOT NULL,
  `active` tinyint(1) NOT NULL,
  `moderated` tinyint(1) NOT NULL,
  PRIMARY KEY (`job_id`),
  KEY `advertiser_id` (`advertiser_id`,`active`,`moderated`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `jobs` (`job_id`, `advertiser_id`, `name`, `shortdesc`, `longdesc`, `address`, `active`, `moderated`) VALUES
(1, 1, 'TEST', 'TESTTEST', 'TESTTESTES', '', 0, 0);

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);
steven
fonte

Respostas:

108

Como é, você deve excluir a linha da tabela de anunciantes antes de poder excluir a linha da tabela de tarefas a que faz referência. Este:

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `jobs` (`advertiser_id`);

... é realmente o oposto do que deveria ser. Assim, significa que você precisaria ter um registro na tabela de tarefas antes dos anunciantes. Então você precisa usar:

ALTER TABLE `jobs`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `advertisers` (`advertiser_id`);

Depois de corrigir o relacionamento de chave estrangeira, sua instrução de exclusão funcionará.

Pôneis OMG
fonte
3
Na primeira linha: você não acha que deveria ser "que faz referência" em vez de "que faz referência"? Ou entendi mal como a terminologia das referências deve funcionar?
Abraham Philip
6
@AbrahamPhilip Eu estava pensando a mesma coisa. anunciantes referencia trabalhos.
quer
270

A maneira mais simples seria desativar a verificação de chave estrangeira; faça as alterações e reative a verificação de chave estrangeira.

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them
Alino Manzi
fonte
171
Esta não é uma solução para o problema, mas uma solução alternativa suja que pode não ser desejada.
madfriend
20
No meu caso: acabei de executar um arquivo SQL grande e uma das instruções finais falhou; portanto, quero excluir todas as tabelas, corrigir o erro de sintaxe e executar novamente, tornando exatamente isso o que estava procurando.
ekerner
1
Se você faria isso, por que não apenas remover todas as restrições?
precisa saber é o seguinte
1
É útil quando se faz algo como:REPLACE INTO tab_with_constraint ...
Maciek Łoziński
5
A única razão para aprovar esta resposta é se você deseja que seu código pare de gritar com você e se aprofunde em espaguete sem entender o código que está escrevendo. O motivo para ter chaves estrangeiras em primeiro lugar é impor a integridade referencial. Se você precisar desativá-las para interromper o código, provavelmente deseja repensar suas chaves estrangeiras, em vez de desativá-las.
Cytinus
38

No seu design atual (possivelmente defeituoso), você deve excluir a linha da tabela de anunciantes antes de excluir a linha na tabela de tarefas a que se refere.

Como alternativa, você pode configurar sua chave estrangeira para que uma exclusão na tabela pai faça com que as linhas nas tabelas filho sejam excluídas automaticamente. Isso é chamado de exclusão em cascata. Parece algo assim:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Dito isto, como outros já apontaram, sua chave estrangeira parece que deve ser inversa, pois a tabela de anunciantes realmente contém a chave primária e a tabela de trabalhos contém a chave estrangeira. Eu reescreveria assim:

ALTER TABLE `jobs`
ADD FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`);

E a exclusão em cascata não será necessária.

Asaph
fonte
18

Se você deseja soltar uma tabela, execute a seguinte consulta em uma única etapa

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE nome_tabela;

Abin John
fonte
13

Tentei a solução mencionada por @Alino Manzi, mas não funcionou para mim nas tabelas relacionadas ao WordPress usando o wpdb.

então eu modifiquei o código como abaixo e funcionou

SET FOREIGN_KEY_CHECKS=OFF; //disabling foreign key

//run the queries which are giving foreign key errors

SET FOREIGN_KEY_CHECKS=ON; // enabling foreign key
Moh .S
fonte
6

Eu acho que sua chave estrangeira está ao contrário. Experimentar:

ALTER TABLE 'jobs'
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`)
Tom H
fonte
5

Se houver mais de um trabalho com o mesmo advertiser_id, sua chave estrangeira deverá ser:

ALTER TABLE `jobs`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `advertisers` (`advertiser_id`);

Caso contrário (se for o contrário, no seu caso), se você desejar que as linhas do anunciante sejam excluídas automaticamente se a linha do trabalho for excluída, adicione a opção 'ON DELETE CASCADE' ao final da sua chave estrangeira:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Confira restrições de chave estrangeira

Usuário SO
fonte
3

Você precisa excluí-lo por ordem. Há dependência nas tabelas

Ran Adler
fonte
2

Quando você cria um banco de dados ou cria tabelas

Você deve adicionar essa linha no script superior para criar banco de dados ou tabela

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;

Agora você deseja excluir registros da tabela? então você escreve como

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1

Boa sorte!

Quy Le
fonte
2

Que tal essa alternativa que estou usando: permita que a chave estrangeira seja NULL e escolha ON DELETE SET NULL .

Pessoalmente, prefiro usar " ON UPDATE CASCADE " e " ON DELETE SET NULL " para evitar complicações desnecessárias, mas na sua configuração você pode querer uma abordagem diferente. Além disso, valores nulos de chave estrangeira podem levar a complicações, pois você não saberá exatamente o que aconteceu lá. Portanto, essa alteração deve estar em estreita relação com o funcionamento do código do aplicativo.

Espero que isto ajude.

Marius Cucuruz
fonte
2

Eu tive esse problema na migração laravel também,
a ordem das tabelas suspensas no método down () importa

Schema::dropIfExists('groups');
Schema::dropIfExists('contact');

pode não funcionar, mas se você alterar a ordem, ela funcionará.

Schema::dropIfExists('contact');
Schema::dropIfExists('groups');
Amin
fonte
1

se você precisar dar suporte ao cliente o mais rápido possível e não tiver acesso a

FOREIGN_KEY_CHECKS

para que a integridade dos dados possa ser desativada:

1) excluir chave estrangeira

ALTER TABLE `advertisers` 
DROP FOREIGN KEY `advertisers_ibfk_1`;

2) ative sua operação de exclusão através de sql ou api

3) adicione a chave estrangeira de volta ao esquema

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);

no entanto, é uma correção, por sua conta e risco, porque a principal falha dessa abordagem é que é necessário posteriormente para manter a integridade dos dados manualmente.

Oleksii Kyslytsyn
fonte
0

Você pode criar um gatilho para excluir as linhas referenciadas antes de excluir o trabalho.

    DELIMITER $$
    CREATE TRIGGER before_jobs_delete 
        BEFORE DELETE ON jobs
        FOR EACH ROW 
    BEGIN
        delete from advertisers where advertiser_id=OLD.advertiser_id;
    END$$
    DELIMITER ;
Patch92
fonte
0

O principal problema com esse erro Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failsé que ele não informa qual tabela contém a falha do FK; portanto, é difícil resolver o conflito.

Se você usa MySQL ou similar, descobri que você pode criar um diagrama de ER para seu banco de dados, então você pode revisar e remover com segurança os conflitos que desencadeiam o erro.

  1. Use o ambiente de trabalho MySQL
  2. Clique em Banco de Dados -> Engenharia Reversa
  3. Selecione um correto connection
  4. Do próximo até o final, lembre-se de selecionar databasee tablesque precisa examinar
  5. Agora você tem o diagrama de ER, pode ver qual tabela tem conflito de FK
Ng Sek Long
fonte
0

Basicamente, a razão por trás desse tipo de erro é eventualmente que você está tentando excluir um par que possui chave primária (tabela raiz) e essa chave primária é usada na tabela filha como chave estrangeira. Nesse cenário, para excluir os dados da tabela pai, é necessário remover os dados da tabela filha (na qual a chave estrangeira é usada). obrigado

kishan99
fonte
0

Isso aconteceu comigo também e, devido a uma dependência e referência de outras tabelas, não foi possível remover a entrada. O que fiz foi adicionado uma coluna de exclusão (do tipo booleano) à tabela. O valor nesse campo mostrou se o item está marcado para exclusão ou não. Se marcado para exclusão, não busque / use; caso contrário, use-o.

Tariq Kamal
fonte
-1

Talvez você deva tentar ON DELETE CASCADE


fonte
34
Adicionar cegamente uma exclusão em cascata (que destruirá os dados) sem entender o problema é a pior coisa que se pode fazer.
Tom H