O MySQL não pode adicionar restrições de chave estrangeira


314

Portanto, estou tentando adicionar restrições de chave estrangeira ao meu banco de dados como um requisito do projeto e funcionou pela primeira vez ou duas em tabelas diferentes, mas tenho duas tabelas nas quais recebo um erro ao tentar adicionar as restrições de chave estrangeira. A mensagem de erro que recebo é:

ERRO 1215 (HY000): Não é possível adicionar restrição de chave estrangeira

Este é o SQL que estou usando para criar as tabelas, as duas tabelas incorretas são Patiente Appointment.

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

CREATE SCHEMA IF NOT EXISTS `doctorsoffice` DEFAULT CHARACTER SET utf8 ;
USE `doctorsoffice` ;

-- -----------------------------------------------------
-- Table `doctorsoffice`.`doctor`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`doctor` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`doctor` (
  `DoctorID` INT(11) NOT NULL AUTO_INCREMENT ,
  `FName` VARCHAR(20) NULL DEFAULT NULL ,
  `LName` VARCHAR(20) NULL DEFAULT NULL ,
  `Gender` VARCHAR(1) NULL DEFAULT NULL ,
  `Specialty` VARCHAR(40) NOT NULL DEFAULT 'General Practitioner' ,
  UNIQUE INDEX `DoctorID` (`DoctorID` ASC) ,
  PRIMARY KEY (`DoctorID`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`medicalhistory`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`medicalhistory` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`medicalhistory` (
  `MedicalHistoryID` INT(11) NOT NULL AUTO_INCREMENT ,
  `Allergies` TEXT NULL DEFAULT NULL ,
  `Medications` TEXT NULL DEFAULT NULL ,
  `ExistingConditions` TEXT NULL DEFAULT NULL ,
  `Misc` TEXT NULL DEFAULT NULL ,
  UNIQUE INDEX `MedicalHistoryID` (`MedicalHistoryID` ASC) ,
  PRIMARY KEY (`MedicalHistoryID`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`Patient`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`Patient` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`Patient` (
  `PatientID` INT unsigned NOT NULL AUTO_INCREMENT ,
  `FName` VARCHAR(30) NULL ,
  `LName` VARCHAR(45) NULL ,
  `Gender` CHAR NULL ,
  `DOB` DATE NULL ,
  `SSN` DOUBLE NULL ,
  `MedicalHistory` smallint(5) unsigned NOT NULL,
  `PrimaryPhysician` smallint(5) unsigned NOT NULL,
  PRIMARY KEY (`PatientID`) ,
  UNIQUE INDEX `PatientID_UNIQUE` (`PatientID` ASC) ,
  CONSTRAINT `FK_MedicalHistory`
    FOREIGN KEY (`MEdicalHistory` )
    REFERENCES `doctorsoffice`.`medicalhistory` (`MedicalHistoryID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_PrimaryPhysician`
    FOREIGN KEY (`PrimaryPhysician` )
    REFERENCES `doctorsoffice`.`doctor` (`DoctorID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`Appointment`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`Appointment` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`Appointment` (
  `AppointmentID` smallint(5) unsigned NOT NULL AUTO_INCREMENT ,
  `Date` DATE NULL ,
  `Time` TIME NULL ,
  `Patient` smallint(5) unsigned NOT NULL,
  `Doctor` smallint(5) unsigned NOT NULL,
  PRIMARY KEY (`AppointmentID`) ,
  UNIQUE INDEX `AppointmentID_UNIQUE` (`AppointmentID` ASC) ,
  CONSTRAINT `FK_Patient`
    FOREIGN KEY (`Patient` )
    REFERENCES `doctorsoffice`.`Patient` (`PatientID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_Doctor`
    FOREIGN KEY (`Doctor` )
    REFERENCES `doctorsoffice`.`doctor` (`DoctorID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`InsuranceCompany`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`InsuranceCompany` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`InsuranceCompany` (
  `InsuranceID` smallint(5) NOT NULL AUTO_INCREMENT ,
  `Name` VARCHAR(50) NULL ,
  `Phone` DOUBLE NULL ,
  PRIMARY KEY (`InsuranceID`) ,
  UNIQUE INDEX `InsuranceID_UNIQUE` (`InsuranceID` ASC) )
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `doctorsoffice`.`PatientInsurance`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `doctorsoffice`.`PatientInsurance` ;

CREATE  TABLE IF NOT EXISTS `doctorsoffice`.`PatientInsurance` (
  `PolicyHolder` smallint(5) NOT NULL ,
  `InsuranceCompany` smallint(5) NOT NULL ,
  `CoPay` INT NOT NULL DEFAULT 5 ,
  `PolicyNumber` smallint(5) NOT NULL AUTO_INCREMENT ,
  PRIMARY KEY (`PolicyNumber`) ,
  UNIQUE INDEX `PolicyNumber_UNIQUE` (`PolicyNumber` ASC) ,
  CONSTRAINT `FK_PolicyHolder`
    FOREIGN KEY (`PolicyHolder` )
    REFERENCES `doctorsoffice`.`Patient` (`PatientID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_InsuranceCompany`
    FOREIGN KEY (`InsuranceCompany` )
    REFERENCES `doctorsoffice`.`InsuranceCompany` (`InsuranceID` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;

USE `doctorsoffice` ;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Respostas:


779

Para encontrar o erro específico, execute o seguinte:

SHOW ENGINE INNODB STATUS;

E olhe na LATEST FOREIGN KEY ERRORseção.

O tipo de dados para a coluna filho deve corresponder exatamente à coluna pai. Por exemplo, uma vez que medicalhistory.MedicalHistoryIDé um INT, Patient.MedicalHistorytambém precisa ser um INT, não um SMALLINT.

Além disso, você deve executar a consulta set foreign_key_checks=0antes de executar a DDL para poder criar as tabelas em uma ordem arbitrária, em vez de precisar criar todas as tabelas pai antes das tabelas filho relevantes.


3
Obrigado, tanto o tipo de dados inconsistency como Foreign_key_checks corrigiram o problema!
— joshuaegclark

30
Foi causado por um agrupamento diferente nas tabelas para mim, um era UTF-8 e o outro era latin1.
— ug_

6
Também tive que me certificar de que eu havia marcado "não assinado", pois esse era um INT não assinado, mesmo que meus tipos e comprimento correspondessem.
— timbrown

1
Minhas tabelas foram criadas automaticamente com o mecanismo MyISAM! Obrigado Ike.
— Captain Hypertext

3
Obrigado. Eu estava tentando set nullexcluir, mas a coluna era not null.
— Matt

143

Eu havia definido um campo como "Não assinado" e outro não. Depois de definir as duas colunas como Não assinado, funcionou.


lol mesmo. O MySQL poderia usar um tratamento de erro mais preciso nesse tipo de coisa.
— dave

82
  • O motor deve ser o mesmo, por exemplo, InnoDB
  • O tipo de dados deve ser o mesmo e com o mesmo comprimento. por exemplo, VARCHAR (20)
  • O conjunto de colunas de agrupamento deve ser o mesmo. Por exemplo, utf8
    Watchout: mesmo que suas tabelas tenham o mesmo agrupamento, as colunas ainda podem ter um diferente.
  • Exclusivo - Chave estrangeira deve se referir ao campo exclusivo (geralmente chave primária) na tabela de referência.

1
Melhor resposta de todos os tempos, depois de tentar quase tudo, descobri que tenho que adicionar explicitamente uniqueà coluna da tabela de referência, mesmo que seja uma Primary Key!!
— Yahya

Sim, a melhor resposta de sempre ... em particular, o primeiro ponto! No meu caso, fiz uma migração (registrada de 2.5.14 a bookd 2.7.2), onde o script de migração não alterou o mecanismo de banco de dados; portanto, ao criar novas tabelas, recebi esse erro.
— Bernhard

Melhor me responda também.
— EngineerCoder

Seria ainda mais impressionante com dicas de como verificar / alterar. Para mim, foi uma diferença de agrupamento em nível de coluna e isso me deu a correção (graças para a idéia!): Stackoverflow.com/questions/1294117/...
— sjgp

18

Tente usar o mesmo tipo de suas chaves primárias - int (11) - nas chaves estrangeiras - smallint (5) - também.

Espero que ajude!


mysql> cria um índice único index_bar_id em foos (bar_id); ... mysql> alterar tabela foos adicionar restrição index_bar_id chave estrangeira (bar_id) referências barras (id); sixarm.com/about/…
— CookieCoder

11

Confirme se a codificação e o agrupamento de caracteres para as duas tabelas são iguais.

No meu próprio caso, uma das tabelas estava usando utf8e a outra estava usando latin1.

Eu tive outro caso em que a codificação era a mesma, mas o agrupamento era diferente. Um utf8_general_cio outroutf8_unicode_ci

Você pode executar este comando para definir a codificação e agrupamento para uma tabela.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Espero que isso ajude alguém.


Bom, @Adegoke, great answer #
— Edwin Ikechukwu Okonkwo

7

Para definir uma CHAVE ESTRANGEIRA na tabela B, você deve definir uma CHAVE na tabela A.

Na tabela A: INDEX id( id)

E então na tabela B,

CONSTRAINT `FK_id` FOREIGN KEY (`id`) REFERENCES `table-A` (`id`)

Não sei exatamente o que você está dizendo, mas achei que minha sintaxe estava incorreta. Eu estava fazendo: alterar tabela aeronave adicionar restrição fk_somehting_unique chave estrangeira (operator_id) organização de referências, mas deveria ter feito: alterar tabela aeronave adicionar restrição fk_somehting_unique chave estrangeira (operator_id) organização de referências (id) ;
— Michael Coxon

7

Eu tive o mesmo problema e a solução foi muito simples. Solução: chaves estrangeiras declaradas na tabela não devem ser definidas como nulas.

referência: se você especificar uma ação SET NULL, certifique-se de não ter declarado as colunas na tabela filha como NOT NULL. ( ref )


4

Verifique as seguintes regras:

  • Primeiro verifica se os nomes são dados corretamente para nomes de tabelas

  • O segundo tipo de dados correto atribui à chave estrangeira?


4

Verifique se as duas tabelas estão no formato InnoDB. Mesmo se alguém estiver no formato MyISAM, a restrição de chave estrangeira não funcionará.

Além disso, outra coisa é que, ambos os campos devem ser do mesmo tipo. Se um é INT, o outro também deve ser INT. Se um é VARCHAR, o outro também deve ser VARCHAR, etc.


3

Eu enfrentei o problema e consegui resolvê-lo, garantindo que os tipos de dados correspondessem exatamente.

Eu estava usando o SequelPro para adicionar a restrição e ela estava tornando a chave primária como não assinada por padrão.


2

Verifique a assinatura nas duas colunas da tabela. Se a coluna da tabela de referência for ASSINADA, a coluna da tabela de referência também deverá ser ASSINADA.


1

NOTA: As tabelas a seguir foram retiradas de algum site quando eu fazia alguma pesquisa e desenvolvimento no banco de dados. Portanto, a convenção de nomenclatura não é adequada.

Para mim, o problema era que minha tabela pai tinha um conjunto de caracteres diferente daquele que eu estava criando.

Tabela pai (PRODUCTS)

products | CREATE TABLE `products` (
  `productCode` varchar(15) NOT NULL,
  `productName` varchar(70) NOT NULL,
  `productLine` varchar(50) NOT NULL,
  `productScale` varchar(10) NOT NULL,
  `productVendor` varchar(50) NOT NULL,
  `productDescription` text NOT NULL,
  `quantityInStock` smallint(6) NOT NULL,
  `buyPrice` decimal(10,2) NOT NULL,
  `msrp` decimal(10,2) NOT NULL,
  PRIMARY KEY (`productCode`),
  KEY `productLine` (`productLine`),
  CONSTRAINT `products_ibfk_1` FOREIGN KEY (`productLine`) REFERENCES `productlines` (`productLine`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Tabela filho que teve um problema (PRICE_LOGS)

price_logs | CREATE TABLE `price_logs` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `productCode` varchar(15) DEFAULT NULL,
  `old_price` decimal(20,2) NOT NULL,
  `new_price` decimal(20,2) NOT NULL,
  `added_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `productCode` (`productCode`),
  CONSTRAINT `price_logs_ibfk_1` FOREIGN KEY (`productCode`) REFERENCES `products` (`productCode`) ON DELETE CASCADE ON UPDATE CASCADE
);

MODIFICADO PARA

price_logs | CREATE TABLE `price_logs` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `productCode` varchar(15) DEFAULT NULL,
  `old_price` decimal(20,2) NOT NULL,
  `new_price` decimal(20,2) NOT NULL,
  `added_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `productCode` (`productCode`),
  CONSTRAINT `price_logs_ibfk_1` FOREIGN KEY (`productCode`) REFERENCES `products` (`productCode`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 


0

Ocorreu um erro semelhante ao criar chave estrangeira em uma tabela Muitos para Muitos, onde a chave primária consistia em 2 chaves estrangeiras e outra coluna normal. Corrigi o problema corrigindo o nome da tabela referenciada, ou seja, empresa, conforme mostrado no código corrigido abaixo:

create table company_life_cycle__history -- (M-M)
(
company_life_cycle_id tinyint unsigned not null,
Foreign Key (company_life_cycle_id) references company_life_cycle(id) ON DELETE    CASCADE ON UPDATE CASCADE,
company_id MEDIUMINT unsigned not null,
Foreign Key (company_id) references company(id) ON DELETE CASCADE ON UPDATE CASCADE,
activity_on date NOT NULL,
PRIMARY KEY pk_company_life_cycle_history (company_life_cycle_id, company_id,activity_on),
created_on datetime DEFAULT NULL,
updated_on datetime DEFAULT NULL,
created_by varchar(50) DEFAULT NULL,
updated_by varchar(50) DEFAULT NULL
);


0

Ocorreu um erro semelhante, mas no meu caso estava faltando declarar o pk como auto_increment.

Para o caso de ser útil para qualquer pessoa


0

Eu recebi o mesmo erro. A causa no meu caso foi:

  1. Criei um backup de um banco de dados via phpmyadmin, copiando o banco de dados inteiro.
  2. Criei um novo banco de dados com o mesmo nome que o antigo banco de dados o selecionou.
  3. Comecei um script SQL para criar tabelas e dados atualizados.
  4. Eu entendi o erro. Além disso, quando eu desabilitei Foreign_key_checks. Embora o banco de dados esteja completamente vazio.

A causa foi: Desde que usei o phpmyadmin para criar algumas chaves estrangeiras no banco de dados renomeado - as chaves estrangeiras foram criadas com um prefixo de nome de banco de dados, mas o prefixo de nome de banco de dados não foi atualizado. Portanto, ainda havia referências no backup-db apontando para o recém-criado db.


0

Minha solução é talvez um pouco embaraçosa e conta a história de por que às vezes você deve olhar para o que tem à sua frente em vez dessas postagens :)

Eu já havia executado um engenheiro avançado antes, o que falhou, o que significava que meu banco de dados já tinha algumas tabelas; então, eu estava sentado tentando consertar falhas de restrições de chave estrangeira tentando garantir que tudo estava perfeito, mas foi executado no tabelas criadas anteriormente, portanto não prevaleceu.


0

Uma causa adicional desse erro ocorre quando suas tabelas ou colunas contêm palavras - chave reservadas :

Às vezes se esquece deles.


0

No meu caso, houve um erro de sintaxe que não foi explicitamente notificado pelo console do MySQL ao executar a consulta. No entanto, SHOW ENGINE INNODB STATUSa LATEST FOREIGN KEY ERRORseção de comando relatou,

  Syntax error close to:

  REFERENCES`role`(`id`) ON DELETE CASCADE) ENGINE = InnoDB DEFAULT CHARSET = utf8

Eu tive que deixar um espaço em branco no meio REFERENCESe rolefazê-lo funcionar.


0

Para mim, foi - você não pode omitir o prefixo da tabela de banco de dados atual se criar um FK para um banco de dados não atual que faça referência ao banco de dados atual:

USE currrent_db;
ALTER TABLE other_db.tasks ADD CONSTRAINT tasks_fk FOREIGN KEY (user_id) REFERENCES currrent_db.users (id);

Se eu omitir "currrent_db". para a tabela de usuários, recebo o erro FK. Interessante que MOSTRE O ESTADO DO MOTOR INNODB; não mostra nada neste caso.


-1

Eu tive esse mesmo problema, corrigi o nome do mecanismo como Innodb nas tabelas pai e filho e corrigi o nome do campo de referência FOREIGN KEY ( c_id) REFERENCES x9o_parent_table( c_id)
e, em seguida, ele funciona bem e as tabelas são instaladas corretamente. Isso será usado por completo para alguém.

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.