Erro 1452 do Mysql - Não é possível adicionar ou atualizar uma linha filho: uma restrição de chave estrangeira falha


237

Estou tendo um problema estranho. Estou tentando adicionar uma chave estrangeira a uma tabela que faça referência a outra, mas está falhando por algum motivo. Com meu conhecimento limitado do MySQL, a única coisa que poderia ser suspeita é que existe uma chave estrangeira em uma tabela diferente que faz referência à que estou tentando referenciar.

Eu fiz uma SHOW CREATE TABLEconsulta nas duas tabelas, sourcecodes_tagsé a tabela com a chave estrangeira, sourcecodesé a tabela referenciada.

CREATE TABLE `sourcecodes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) unsigned NOT NULL,
 `language_id` int(11) unsigned NOT NULL,
 `category_id` int(11) unsigned NOT NULL,
 `title` varchar(40) CHARACTER SET utf8 NOT NULL,
 `description` text CHARACTER SET utf8 NOT NULL,
 `views` int(11) unsigned NOT NULL,
 `downloads` int(11) unsigned NOT NULL,
 `time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 KEY `user_id` (`user_id`),
 KEY `language_id` (`language_id`),
 KEY `category_id` (`category_id`),
 CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

CREATE TABLE `sourcecodes_tags` (
 `sourcecode_id` int(11) unsigned NOT NULL,
 `tag_id` int(11) unsigned NOT NULL,
 KEY `sourcecode_id` (`sourcecode_id`),
 KEY `tag_id` (`tag_id`),
 CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Este é o código que gera o erro:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

2
você também pode postar seu comando de inserção / atualização que resulta no erro?
Zed

64
suas tabelas estão vazias quando você adiciona essa chave estrangeira?
Zed

12
tente executar esta consulta para verificar se existe algum código-fonte_id que não seja um ID real: SELECT código-fonte_id FROM código-fonte_categorias WHERE código-fonte NÃO ESTÁ IN (SELECIONE ID DO código-fonte AS tmp);
Zed

11
Obrigado Zed, esse foi o problema em que uma das tabelas tinha dados. Pensando nisso agora, faz sentido que estava falhando porque havia coisas que referenciavam itens inexistentes, mas eu nunca imaginaria isso. Obrigado!
Zim

2
Por que falha se a tabela está vazia?
precisa

Respostas:


226

Provavelmente, sua sourcecodes_tagstabela contém sourcecode_idvalores que não existem mais em sua sourcecodestabela. Você tem que se livrar deles primeiro.

Aqui está uma consulta que pode encontrar esses IDs:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;

UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)deve ajudar a se livrar desses IDs. Ou, se nullnão for permitido entrar sourcecode_id, remova essas linhas ou adicione esses valores ausentes à sourcecodestabela.
NaXa

Eu estava pensando o mesmo, mas, para mim SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULL, não retorna nada, então o problema está em outro lugar !?
Meloman

Ahh, esse foi o problema para mim. Eu estava tentando executar UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;, o que não envolvia uma chave estrangeira, então fiquei confuso. Mas o fato de minha tabela de contatos estar ausente de alguns registros aos quais a tabela de automações se referiu fez com que este fosse "Código de erro: 1452. Não é possível adicionar ou atualizar uma linha filho: uma restrição de chave estrangeira falha".
Ryan Ryan

99

Eu tive o mesmo problema com meu banco de dados MySQL, mas finalmente consegui uma solução que funcionou para mim.
Como na minha tabela tudo estava bem do ponto de vista do mysql (ambas as tabelas devem usar o mecanismo InnoDB e o tipo de dados de cada coluna deve ser do mesmo tipo que participa da restrição de chave estrangeira).
A única coisa que fiz foi desabilitar a verificação da chave estrangeira e, posteriormente, habilitá-la após executar a operação da chave estrangeira.
Etapas que tomei:

SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8  Duplicates: 0  Warnings: 0
SET foreign_key_checks = 1;

49
Foreign_key_checks existem por um motivo. Se você não pode adicionar a chave estrangeira porque ela viola a restrição, corrija os dados primeiro. Desativar verificações e adicionar a chave deixa você em um estado inconsistente. As verificações de chave estrangeira adicionam sobrecarga, se você não quiser usá-las, use o myisam.
cs_alumnus

5
@AbuSadatMohammedYasin não, não deveria: a pergunta era "o que está acontecendo" e esta resposta simplesmente não tenta explicá-la. Como cs_alumnus mencionou, há um problema maior: todos os novos valores que devem fazer referência a outro valor na outra tabela (como uma chave estrangeira deve fazer) podem apontar para nada, criando um estado inconsistente. A explicação curta e eficaz de Cayetano permite encontrar quais valores você deve atualizar antes de criar a restrição, para que você não se surpreenda com as consultas que devem retornar valores que deveriam existir!
Armfoot

55

Use NOT INpara descobrir onde as restrições estão restringindo :

SELECT column FROM table WHERE column NOT IN 
(SELECT intended_foreign_key FROM another_table)

então, mais especificamente:

SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN 
(SELECT id FROM sourcecodes)

EDIT: INe NOT INsabe-se que os JOINoperadores são muito mais rápidos que os operadores, bem como muito mais fáceis de construir e repetir.


1
Portanto, se eu entendi isso corretamente, podemos adicionar uma chave estrangeira a uma tabela que já possui dados, mas apenas se existir uma linha filho para cada linha na tabela pai? Se não houver linhas filho para cada linha na tabela pai (que é o que sua consulta descobre), o script da chave estrangeira falhará.
Vincent

@Vincent se por tabela pai você quer dizer a tabela sendo referenciada, então sim! Portanto, com o Cayetano's select, você obtém todas as linhas necessárias para atualizar / remover da tabela "filho" antes de adicionar a nova restrição (FK). Quando todos apontarem para valores na "outra_tabela", você estará pronto!
Armfoot

23

Trunque as tabelas e tente adicionar a restrição FK .

Eu sei que esta solução é um pouco estranha, mas funciona 100%. Mas concordo que essa não é uma solução ideal para lidar com o problema, mas espero que ajude.


4
Não há necessidade de truncar tudo. "UPDATE sourcecodes_tags SET sourcecode_id = NULL ONDE sourcecode_id NOT IN (SELECT id FROM código de origem)" deve ser suficiente. Ou, se nulo não for permitido em "sourcecode_id", remova essas linhas ou adicione esses valores ausentes à tabela "sourcecodes".
Torben

1
Às vezes, se os dados aumentarem a PK de incremento automático, você será forçado a truncar.
François Breton

2
@ ShankarDamodaran não sabe por que truncar a tabela funciona, mas essa solução funcionou bem para mim. Consegui fazer meus relacionamentos funcionarem ... OBRIGADO!
MizAkita 11/04

@MizAkita funciona porque exclui as linhas que não têm valor correspondente na outra tabela, permitindo que a nova restrição seja criada. Se você acabou de encontrar essas linhas e atualizar ou excluí-los (como a sugestão de Cayetano ), você não precisa excluir as outras linhas ...
Armfoot

@ Armfoot - Eu tive esse problema ao adicionar a primeira linha à tabela com chave estrangeira. Portanto, eu não tinha linhas para pesquisar.
Krewetka #

16

Para mim, esse problema era um pouco diferente e super fácil de verificar e resolver.

Você deve garantir que ambas as suas tabelas sejam o InnoDB. Se uma das tabelas, ou seja, a tabela de referência for um MyISAM, a restrição falhará.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;

14

Isso também acontece ao definir uma chave estrangeira como parent.id como child.column se o child.column já tiver um valor 0 e nenhum valor parent.id for 0

Você precisaria garantir que cada child.column seja NULL ou tenha um valor que exista em parent.id

E agora que li a declaração que nos escreveu, é isso que ele está validando.


14

Eu tive o mesmo problema hoje. Eu testei para quatro coisas, algumas delas já mencionadas aqui:

  1. Há algum valor na coluna filho que não exista na coluna pai (além de NULL, se a coluna filha for anulável)

  2. As colunas filho e pai têm o mesmo tipo de dados?

  3. Existe um índice na coluna pai que você está referenciando? O MySQL parece exigir isso por razões de desempenho ( http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html )

  4. E este resolveu para mim: as duas tabelas têm agrupamento idêntico?

Eu tinha uma mesa em UTF-8 e a outra em iso-something. Isso não funcionou. Após alterar a tabela iso para agrupamento UTF-8, as restrições podem ser adicionadas sem problemas. No meu caso, o phpMyAdmin nem mostrou a tabela filho em iso-codificação no menu suspenso para criar a restrição de chave estrangeira.


7

Parece que existe algum valor inválido para a linha de coluna 0 que não é uma chave estrangeira válida, portanto o MySQL não pode definir uma restrição de chave estrangeira para ela.

Você pode seguir estas etapas:

  1. Solte a coluna para a qual você tentou definir a restrição FK.

  2. Adicione-o novamente e defina seu valor padrão como NULL.

  3. Tente definir uma restrição de chave estrangeira para ele novamente.


5

Eu tinha o mesmo problema, verifiquei as linhas das minhas tabelas e descobri que havia alguma incompatibilidade com o valor dos campos que eu queria definir uma chave estrangeira. Corrigi esses valores, tentei novamente e o problema foi resolvido.


4

Acabo excluindo todos os dados da minha tabela e execute alter novamente. Funciona. Não é o mais brilhante, mas economiza muito tempo, especialmente seu aplicativo ainda está em estágio de desenvolvimento sem dados de clientes.


4

tente isso

SET foreign_key_checks = 0;

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

SET foreign_key_checks = 1;

2

Eu tive exatamente esse mesmo problema em três momentos diferentes. Em cada caso, foi porque um (ou mais) dos meus registros não estava em conformidade com a nova chave estrangeira. Convém atualizar seus registros existentes para seguir as restrições de sintaxe da chave estrangeira antes de tentar adicionar a própria chave. O exemplo a seguir geralmente deve isolar os registros do problema:

SELECT * FROM (tablename)
    WHERE (candidate key) <> (proposed foreign key value) 
        AND (candidate key) <> (next proposed foreign key value)

repita AND (candidate key) <> (next proposed foreign key value)na sua consulta para cada valor na chave estrangeira.

Se você possui muitos registros, isso pode ser difícil, mas se sua tabela for razoavelmente pequena, não deve demorar muito. Não sou super incrível na sintaxe SQL, mas isso sempre isolou o problema para mim.


2

Esvazie os dados de ambas as tabelas e execute o comando Vai funcionar.


VHanded deu a mesma resposta há 3 anos. Vamos torcer para que não havia quaisquer dados importantes nas tabelas ...
xlecoustillier


1

Eu estava preparando essas soluções e este exemplo pode ajudar.

Meu banco de dados possui duas tabelas (email e credit_card) com chaves primárias para seus IDs. Outra tabela (cliente) refere-se aos IDs dessa tabela como chaves estrangeiras. Eu tenho um motivo para separar o email dos dados do cliente.

Primeiro insiro os dados da linha para as tabelas referenciadas (email, credit_card) e, em seguida, você obtém o ID de cada um, esses IDs são necessários na terceira tabela (cliente).

Se você não inserir primeiro as linhas nas tabelas referenciadas, o MySQL não poderá fazer as correspondências quando você inserir uma nova linha na terceira tabela que faça referência às chaves estrangeiras.

Se você primeiro inserir as linhas referenciadas nas tabelas referenciadas, a linha que se refere a chaves estrangeiras, nenhum erro ocorrerá.

Espero que isto ajude.


mysql> insira em valores de email (email) ('xxx@yyy.com'); mysql> inserir em valores ndtc (ndtc, ano, mês) ('1111222233334444', '2000', '01'); mysql> insira no cliente (nombres, apellidos, telefono, idNDTC, idEmail) os valores ('myname', 'myapp', '5555555555', 1,1);
SubstanceMX

1

Verifique se o valor está na outra tabela, caso contrário você receberá esse erro na coluna correspondente atribuída.

Portanto, se a coluna atribuída estiver atribuída a um ID de linha de outra tabela, verifique se há uma linha na tabela, caso contrário, esse erro será exibido.


1

você pode tentar este exemplo

 START TRANSACTION;
 SET foreign_key_checks = 0;
 ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY 
 (`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 SET foreign_key_checks = 1;
 COMMIT;

Nota: se você estiver usando o phpmyadmin, desmarque a opção Ativar verificações de chave estrangeira

como exemplo insira a descrição da imagem aqui

espero que esta solução resolva seu problema :)


1

Você só precisa responder uma pergunta:

Sua tabela já está armazenando dados? (Especialmente a tabela inclui chave estrangeira.)

Se a resposta for afirmativa, a única coisa que você precisa fazer é excluir todos os registros, e poderá adicionar qualquer chave estrangeira à sua tabela.

Excluir instrução: do filho (que inclui tabela de chaves estrangeiras) para a tabela pai.

O motivo pelo qual você não pode adicionar uma chave estrangeira após a entrada de dados é devido à inconsistência da tabela. Como você lida com uma nova chave estrangeira nos dados anteriores preenchidos na tabela?

Se a resposta for não, siga as outras instruções.


0
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

deve ajudar a se livrar desses IDs. Ou, se nullnão for permitido entrar sourcecode_id, remova essas linhas ou adicione esses valores ausentes à sourcecodestabela.


0

Eu tive o mesmo problema e encontrei a solução, colocando em NULLvez da NOT NULLcoluna de chave estrangeira. Aqui está uma consulta:

ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;

O MySQL executou esta consulta!


0

No meu caso, criei uma nova tabela com a mesma estrutura, criei os relacionamentos com as outras tabelas, extraí os dados no CSV da tabela antiga com o problema, depois importei o CSV para a nova tabela e desabilitei a verificação de chave estrangeira e interrupção de importação desativada, todos os meus dados são inseridos na nova tabela que não apresenta problemas com êxito e, em seguida, excluídos da tabela antiga.

Funcionou para mim.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.