MySQL Yabancı Anahtar Kısıtı Ekleyemiyor


314

Bu yüzden bir proje gereksinimi olarak benim veritabanı için Yabancı Anahtar kısıtlamaları eklemeye çalışıyorum ve farklı tablolarda ilk veya iki kez çalıştı, ama Yabancı Anahtar Kısıtlamaları eklemeye çalışırken bir hata alıyorum iki tablo var. Aldığım hata iletisi:

HATA 1215 (HY000): Yabancı anahtar kısıtlaması eklenemiyor

Bu tabloları oluşturmak için kullandığım SQL, iki rahatsız edici tablo Patientve 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;

Yanıtlar:


779

Belirli bir hatayı bulmak için şunu çalıştırın:

SHOW ENGINE INNODB STATUS;

Ve LATEST FOREIGN KEY ERRORbölüme bakın.

Alt sütunun veri türü, üst sütunla tam olarak eşleşmelidir. Çünkü Örneğin, medicalhistory.MedicalHistoryIDbir olduğunu INT, Patient.MedicalHistoryaynı zamanda bir olması gerekir INT, değil SMALLINT.

Ayrıca, set foreign_key_checks=0DDL'yi çalıştırmadan önce sorguyu çalıştırmalısınız, böylece ilgili alt tablolardan önce tüm üst tabloları oluşturmak yerine tabloları rasgele bir sırada oluşturabilirsiniz.


3
Teşekkürler, hem veri türü tutarsızlığı hem de foreign_key_checks sorunu çözdü!
joshuaegclark

30
Tablolar benim için farklı bir harmanlama neden oldu, biri UTF-8 ve diğeri latin1 oldu.
ug_

6
Ayrıca benim türleri ve uzunluğu eşleşen bile bu imzasız bir INT olduğundan "imzasız" kontrol emin olmak zorunda kaldı.
timbrown

1
Tablolarım otomatik olarak MyISAM motoruyla oluşturuluyordu! Teşekkürler Ike.
Kaptan Hypertext

3
Teşekkürler. Silmeye çalışıyordum set null, ama sütun öyleydi not null.
Matt

142

Bir alanı "İmzasız" olarak, diğerini de ayarlamamıştım. Her iki sütunu da İmzasız olarak ayarladıktan sonra çalıştı.


lol aynı. MySQL, bu tür şeylerde daha kesin hata işleme kullanabilir.
dave

82
  • Motor aynı olmalıdır, örneğin InnoDB
  • Veri tipi aynı ve aynı uzunlukta olmalıdır. örneğin VARCHAR (20)
  • Harmanlama Sütun karakter kümesi aynı olmalıdır. örneğin utf8
    Watchout: Tablolarınız aynı Harmanlama'ya sahip olsa bile, sütunlar yine de farklı olabilir.
  • Benzersiz - Yabancı anahtar , başvuru tablosunda benzersiz olan alana (genellikle birincil anahtar) başvurmalıdır .

1
Şimdiye Kadarki En İyi Cevap, Hemen hemen her şeyi denedikten sonra, açıkça bir uniquereferans tablosu sütununa eklemek zorunda olduğum ortaya çıktı Primary Key!
Yahya

Evet, şimdiye kadarki en iyi cevap ... özellikle köknar ilk nokta! Benim durumumda, geçiş komut dosyasının veritabanı motorunu değiştirmediği bir geçiş (2.5.14 için bookd 2.7.2'ye rezervasyonu) yaptım, bu yüzden yeni tablolar oluştururken bu hatayı aldım.
Bernhard

Bana da en iyi cevap.
EngineerCoder

Nasıl kontrol / değiştirme ipuçları ile daha harika olurdu. Benim için sütun düzeyinde bir Harmanlama
farkıydı

18

Aynı tür birincil anahtarlarınızı ( int (11)) yabancı anahtarlarda - smallint (5) - kullanmaya çalışın .

Umarım yardımcı olur!


mysql> foos üzerinde benzersiz dizin oluştur index_bar_id (bar_id); ... mysql> tablo değiştir foos kısıtlama ekle index_bar_id yabancı anahtar (bar_id) referanslar bars (id); sixarm.com/about/…
CookieCoder

11

İki tablo için karakter kodlaması ve harmanlamanın aynı olduğunu onaylayın.

Kendi durumumda, tablolardan biri kullanıyordu utf8ve diğeri kullanıyordu latin1.

Kodlamanın aynı olduğu ancak harmanlamanın farklı olduğu başka bir durum daha vardı. Biri utf8_general_cidiğeriutf8_unicode_ci

Bir tablonun kodlamasını ve harmanlamasını ayarlamak için bu komutu çalıştırabilirsiniz.

ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;

Umarım bu birine yardımcı olur.


Güzel bir @Adegoke, harika cevap
Edwin Ikechukwu

7

Tablo B'de bir YABANCI TUŞU ayarlamak için A tablosunda bir TUŞ ayarlamanız gerekir.

Tablo A'da: INDEX id( id)

Ve sonra B tablosunda,

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

tam olarak ne dediğini bilmiyorum ama benim sözdizimin yanlış olduğunu gördüm. Ben yapıyordum: alter tablo uçak kısıtlama fk_somehting_unique yabancı anahtar (operator_id) referansları organizasyon eklemek, ama yapmalıydım: alter tablo uçak kısıtlama fk_somehting_unique yabancı anahtar (operator_id) referansları organizasyon (id) ekleyin ;
Michael Coxon

7

Aynı problemim vardı ve çözüm çok basitti. Çözüm: tabloda belirtilen yabancı anahtarlar boş değerli olmamalıdır.

başvuru: SET NULL eylemini belirtirseniz, alt tablodaki sütunları NULL DEĞİL olarak bildirmediğinizden emin olun. ( ref )


4

Aşağıdaki kuralları kontrol edin:

  • İlk olarak tablo isimleri için isimlerin doğru verilip verilmediğini kontrol eder

  • İkinci doğru veri türü yabancı anahtara verir mi?


4

Lütfen her iki tablonun da InnoDB formatında olduğundan emin olun. Biri MyISAM biçiminde olsa bile, yabancı anahtar kısıtlaması işe yaramaz.

Ayrıca, başka bir şey, her iki alanın da aynı türde olması gerektiğidir. Biri INT ise, diğeri de INT olmalıdır. Biri VARCHAR ise, diğeri de VARCHAR vb. Olmalıdır.


3

Sorunla karşılaştım ve veri türlerinin tam olarak eşleştiğinden emin olarak çözebildim.

Kısıtlama eklemek için SequelPro kullanıyordum ve birincil anahtarı varsayılan olarak imzasız olarak yapıyordu.


2

Her iki tablo sütununuzdaki imzalamayı kontrol edin. Yönlendirme tablosu sütunu SIGNED ise, başvurulan tablo sütunu da SIGNED olmalıdır.


1

NOT: Veritabanında Ar-Ge yaparken aşağıdaki tablolar bazı sitelerden alınmıştır. Yani adlandırma kuralı uygun değil.

Benim için sorun şuydu: Ana tablom, oluşturduğumdan farklı karakter kümesine sahipti.

Ana Tablo (ÜRÜNLER)

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

Sorunu olan Çocuk Masası (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
);

DEĞİŞTİRİLDİ

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 

1

Benim sorunum diğer tablolardan önce ilişki tablo oluşturmaya çalışıyordu oldu!


SET foreign_key_checks = 0;
LeeGee

0

Birincil anahtarın 2 yabancı anahtardan ve başka bir normal sütundan oluştuğu Çoktan Çokya tablosunda yabancı anahtar oluşturmada benzer bir hata yaşadım. Aşağıdaki düzeltilmiş kodda gösterildiği gibi başvurulan tablo adını yani şirket, düzelterek sorunu düzeltti:

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

Benzer bir hata vardı, ama benim durumumda pk auto_increment olarak bildirmek için eksikti.

Herkes için yararlı olabilirse


0

Aynı hatayı aldım. Benim durumumdaki neden:

  1. Tüm veritabanını kopyalayarak phpmyadmin aracılığıyla bir veritabanı yedeği oluşturdum.
  2. Ben eski db und seçti aynı adı ile yeni bir db yarattı.
  3. Güncellenmiş tablolar ve veriler oluşturmak için bir SQL komut dosyası başlattım.
  4. Hatayı aldım. Ayrıca foreign_key_checks devre dışı bırakıldığında. Veritabanı tamamen boş olmasına rağmen.

Nedeni: Yeniden adlandırılan veritabanında bazı yabancı anahtarlar oluşturmak için phpmyadmin kullandığı için - bir veritabanı adı öneki ile oluşturulmuş yabancı anahtarlar, ancak veritabanı adı öneki güncellenmedi. Yani backup-db'de yeni oluşturulan db'ye işaret eden referanslar hala vardı.


0

Benim çözümüm belki biraz utanç verici ve neden bazen bu mesajlar yerine önünüzde olanlara bakmanız gerektiğini anlatıyor :)

Daha önce bir ileri mühendis koştum, bu da başarısız oldu, bu yüzden veritabanımın zaten birkaç tablo olduğu anlamına geliyordu, o zaman her şeyin mükemmel olduğundan emin olmak için çalışırken yabancı anahtar kontraksiyon hatalarını düzeltmeye çalışıyordum, ancak tablolar daha önce oluşturulmuş, bu yüzden geçerli değildi.


0

Bu hatanın ek bir nedeni, tablolarınız veya sütunlarınız ayrılmış anahtar kelimeler içeriyorsa :

Bazen biri bunları unutur.


0

Benim durumumda, sorguyu çalıştırdıktan sonra MySQL konsolu tarafından açıkça bildirilmeyen bir sözdizimi hatası oluştu. Ancak, SHOW ENGINE INNODB STATUSkomutun LATEST FOREIGN KEY ERRORbölümünde bildirilen,

  Syntax error close to:

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

Aralarında bir boşluk bırakmak REFERENCESve onu çalıştırmak zorunda kaldım role.


0

Benim için öyleydi - geçerli DB'ye atıfta mevcut olmayan bir DB için bir FK oluşturursanız, geçerli DB tablosunun önekini atlayamazsınız:

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

"Currrent_db" yi atlarsam. kullanıcılar tablosu için, FK hatası alıyorum. İlginçtir MOTOR INNODB DURUMU GÖSTER; bu durumda hiçbir şey göstermez.


-1

Ben aynı sorunu vardı sonra hem üst hem de alt tablolarda Motorod Innodb düzeltildi ve referans alan adı DIŞ ANAHTAR ( c_id) REFERANSLAR x9o_parent_table( c_id) düzeltilmiş
sonra iyi çalışır ve tablolar doğru yüklenir. Bu birisi için dolu olacak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.