MySQL Foreign Keys ile tablo oluşturma hatası: 150


98

MySQL'de diğer 2 tablodaki birincil anahtarlara başvuran iki yabancı anahtarla bir tablo oluşturmaya çalışıyorum, ancak bir hata alıyorum: 150 hatası ve tabloyu oluşturmayacak.

İşte 3 tablonun tümü için SQL:

CREATE TABLE role_groups (
  `role_group_id` int(11) NOT NULL `AUTO_INCREMENT`,
  `name` varchar(20),
  `description` varchar(200),
  PRIMARY KEY (`role_group_id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `roles` (
  `role_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50),
  `description` varchar(200),
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB;

create table role_map (
  `role_map_id` int not null `auto_increment`,
  `role_id` int not null,
  `role_group_id` int not null,
  primary key(`role_map_id`),
  foreign key(`role_id`) references roles(`role_id`),
  foreign key(`role_group_id`) references role_groups(`role_group_id`)
) engine=InnoDB;

Herhangi bir yardım çok takdir edilecektir.


1
Hata çıktısını gönderebilir ve hangi komutun (üçünün) hataya neden olduğunu söyleyebilir misiniz?
dave

4
Geri tik taklar ne durumda auto_increment? Bu geçerli değil. Otomatik artırma bir tanımlayıcı değil, bir anahtar kelimedir.
Bill Karwin

Yanıtlar:


239

Ben de aynı sorunu yaşadım ALTER TABLE ADD FOREIGN KEY.

Bir saat sonra, 150 numaralı hatayı almamak için bu koşulların yerine getirilmesi gerektiğini öğrendim:

  1. Başvurmak için bir yabancı anahtar tanımlamadan önce Ana tablo mevcut olmalıdır. Tabloları doğru sırada tanımlamalısınız: Önce üst tablo, sonra Alt tablo. Her iki tablo da birbirine başvuruyorsa, FK kısıtlamaları olmayan bir tablo oluşturmalı, ardından ikinci tabloyu oluşturmalı, ardından FK kısıtlamasını ile ilk tabloya eklemelisiniz ALTER TABLE.

  2. İki tablonun her ikisi de yabancı anahtar kısıtlamalarını desteklemelidir, yani ENGINE=InnoDB. Diğer depolama motorları, yabancı anahtar tanımlarını sessizce yok sayarlar, bu nedenle hata veya uyarı vermezler, ancak FK kısıtlaması kaydedilmez.

  3. Ana tabloda başvurulan sütunlar, bir anahtarın en soldaki sütunları olmalıdır. Üstteki anahtar PRIMARY KEYveya ise en iyisi UNIQUE KEY.

  4. FK tanımı, PK sütununa / sütunlarına PK tanımıyla aynı sırada başvurmalıdır. Örneğin, FK ise, Ebeveynin REFERENCES Parent(a,b,c)PK'si sırayla sütunlarda tanımlanmamalıdır (a,c,b).

  5. Ana tablodaki PK sütunları, Alt tablodaki FK sütunları ile aynı veri türünde olmalıdır. Örneğin, Üst tablodaki bir PK sütunu ise, Alt tablo alanında karşılık gelen sütun UNSIGNEDiçin tanımladığınızdan emin olun UNSIGNED.

    İstisna: dizelerin uzunluğu farklı olabilir. Örneğin, VARCHAR(10)referans verebilir VARCHAR(20)veya tam tersi olabilir.

  6. Dize tipi FK sütunları, karşılık gelen PK sütunları ile aynı karakter kümesine ve harmanlamaya sahip olmalıdır.

  7. Alt tabloda zaten veri varsa, FK sütunlarındaki her değer Üst tablo PK sütunundaki / sütunlarındaki bir değerle eşleşmelidir. Bunu aşağıdaki gibi bir sorgu ile kontrol edin:

    SELECT COUNT(*) FROM Child LEFT OUTER JOIN Parent ON Child.FK = Parent.PK 
    WHERE Parent.PK IS NULL;

    Bu sıfır (0) eşleşmeyen değerler döndürmelidir. Açıkçası, bu sorgu genel bir örnektir; tablo adlarınızı ve sütun adlarınızı değiştirmelisiniz.

  8. Ne Ebeveyn masası ne de Alt masa bir TEMPORARYmasa olabilir.

  9. Ne Ebeveyn masası ne de Alt masa bir PARTITIONEDmasa olabilir.

  10. ON DELETE SET NULLSeçenek ile bir FK bildirirseniz, FK sütunları null yapılabilir olmalıdır.

  11. Bir yabancı anahtar için bir kısıtlama adı bildirirseniz, kısıtlama adı yalnızca kısıtlamanın tanımlandığı tabloda değil, tüm şemada benzersiz olmalıdır. İki tablonun aynı ada sahip kendi kısıtlamaları olmayabilir.

  12. Diğer tablolarda yeni FK oluşturmaya çalıştığınız aynı alana işaret eden başka FK'ler varsa ve bunlar hatalı biçimlendirilmişse (yani farklı harmanlama), önce bunların tutarlı hale getirilmesi gerekecektir. Bu, SET FOREIGN_KEY_CHECKS = 0;yanlışlıkla tanımlanan tutarsız bir ilişkiyle kullanıldığı geçmişteki değişikliklerin bir sonucu olabilir . Bu sorunlu FK'lerin nasıl tanımlanacağına ilişkin talimatlar için aşağıdaki @ andrewdotn yanıtına bakın.

Bu yardımcı olur umarım.


4
Eklemeye değer bir şey daha: üst tablonun PK'si birden fazla
Kip

26
Buna int(11) unsigned NOT NULLvs gibi şeyler dahildir int(11) NOT NULL.
Glen Solsberry

4
ALTER TABLE table_name ENGINE = InnoDB;
TolMera

12
Tablo ENGINE = MyISAM olarak tanımlanmışsa, yabancı anahtar bildirimlerini görmezden geldiğinden 150 hatası üretmez . Otomobil motorunuzla ilgili sorunlardan kaçınmanın en iyi yolu bir tekne kullanmaktır demek gibi. :-)
Bill Karwin

2
Ayrıca, eğer CONSTRAINT'inizin ON DELETEkuralı ise SET NULL, yabancı anahtarın gerçekten NULL olabileceğinden emin olun! Bu cevabı defalarca okuyarak 30 dakika harcadım, tablolarımın koşulları karşıladığından emin oldum ama yine de Hata 150 alıyorum. Sonra fark ettim ki FK'm NOT BOŞ bir alan, yani kuralın uygulanması imkansızdı.
Martin Joiner

62

MySQL'in genel "errno 150" mesajı " yabancı anahtar kısıtlamasının doğru şekilde oluşturulmadığı anlamına gelir ." Muhtemelen zaten bu sayfayı okuyup okumadığınızı bildiğiniz gibi, genel "errno: 150" hata mesajı gerçekten yardımcı olmuyor. Ancak:

Çalıştırarak ve ardından arayarak gerçek hata mesajını alabilirsiniz.SHOW ENGINE INNODB STATUS;LATEST FOREIGN KEY ERROR çıktıda.

Örneğin, bu bir yabancı anahtar kısıtlaması oluşturma girişimi:

CREATE TABLE t1
(id INTEGER);

CREATE TABLE t2
(t1_id INTEGER,
 CONSTRAINT FOREIGN KEY (t1_id) REFERENCES t1 (id));

hata ile başarısız olur Can't create table 'test.t2' (errno: 150). Bu, yabancı anahtar sorunu dışında kimseye yararlı bir şey söylemez. Ama koş SHOW ENGINE INNODB STATUS;ve şöyle diyecek:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
130811 23:36:38 Error in foreign key constraint of table test/t2:
FOREIGN KEY (t1_id) REFERENCES t1 (id)):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.

Sorunun bir dizin bulamaması olduğunu söylüyor. SHOW INDEX FROM t1tablo için hiç dizin olmadığını gösterir t1. Örneğin, bir birincil anahtar tanımlayarak bunu düzeltin t1ve yabancı anahtar kısıtlaması başarıyla oluşturulacaktır.


4
SHOW ENGINE INNODB STATUSYaklaşık bir saattir teşhis etmeye çalıştığım bir sorunu hemen belirlememe yardımcı oldu. Teşekkürler.
jatrim

Benim durumumda, bu belirtilenden ben noktaya çalışıyordu aynı alan tutarsız ve böylece yeni bir tasarruf ... Bu varsayarak kullanmaktan oldu olmaz FK'd o tamamen farklı bir tablo SET FOREIGN_KEY_CHECKS = 0;biçimi bozuk olduğu bir ithalat / değiştirilmesi sırasında bir anda. Büyük yardım, teşekkürler.
oucil

25

Bir kısıtlamaya bağlamaya çalıştığınız iki alanın özelliklerinin tamamen aynı olduğundan emin olun.

Genellikle, bir kimlik sütunundaki 'imzasız' özellik sizi yakalayacaktır.

ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;

Deneyimlerime göre, ana indeks sütununuzda tam olarak hangi bayrakların ayarlandığını kontrol etmek için ana tablonuzda MySQL'in SHOW CREATE TABLE'sini kullanmaya değer, ardından bunları yabancı anahtar sütununuza kopyalayın. Orada açık olmayan "imzasız" gibi şeyler olabilir.
Ambulare

10

Bu komut dosyasını çalıştırdığınızda veritabanınızın mevcut durumu nedir? Tamamen boş mu? Sıfırdan bir veritabanı oluştururken SQL'iniz benim için iyi çalışıyor, ancak errno 150 genellikle bir yabancı anahtarın parçası olan tabloları düşürmek ve yeniden oluşturmakla ilgilidir. % 100 yeni ve yeni bir veritabanıyla çalışmadığınızı hissediyorum.

SQL dosyanızı "kaynak" oluştururken hata yapıyorsanız, daha ayrıntılı hata bilgilerini görmek için "kaynak" komutundan hemen sonra MySQL komut isteminden "SHOW ENGINE INNODB STATUS" komutunu çalıştırabilmelisiniz.

Manuel girişi de kontrol etmek isteyebilirsiniz:

Bırakılan bir tabloyu yeniden oluşturursanız, ona başvuran yabancı anahtar kısıtlamalarına uyan bir tanımı olmalıdır. Daha önce belirtildiği gibi, doğru sütun adlarına ve türlerine sahip olmalı ve başvurulan anahtarlarda dizinlere sahip olmalıdır. Bunlar tatmin edilmezse, MySQL 1005 hata numarasını döndürür ve hata mesajında ​​150 numaralı hatayı belirtir. MySQL, CREATE TABLE ifadesinden 1005 hata numarasını bildirirse ve hata mesajı 150 numaralı hatayı gösterirse, yabancı anahtar kısıtlaması doğru şekilde oluşturulmadığından tablo oluşturma başarısız olur.

- MySQL 5.1 başvuru kılavuzu .


5

Bu konuyu aynı sorunla görüntüleyen kişiler için:

Bunun gibi hatalar almanın birçok nedeni vardır. MySQL'deki yabancı anahtar hatalarının nedenleri ve çözümlerinin oldukça eksiksiz bir listesi için (burada tartışılanlar dahil), şu bağlantıya bakın:

MySQL Yabancı Anahtar Hataları ve Errno 150


4

Bu SO girişini Google aracılığıyla bulan diğerleri için: "NOT NULL" olarak tanımlanan bir yabancı anahtar (olacak) sütununda NULL SET eylemi yapmaya çalışmadığınızdan emin olun. Bu, bir CHECK ENGINE INNODB STATUS'u yapmayı hatırlayana kadar büyük hayal kırıklığına neden oldu.


3

Kesinlikle durum böyle değil, ancak bu hatayı oldukça yaygın ve açık buldum. A'nın hedefi FOREIGN KEYolamazdı PRIMARY KEY. Benim için faydalı hale gelen cevap:

YABANCI ANAHTAR her zaman diğer tablonun bir PRIMARY KEY gerçek alanına işaret edilmelidir.

CREATE TABLE users(
   id INT AUTO_INCREMENT PRIMARY KEY,
   username VARCHAR(40));

CREATE TABLE userroles(
   id INT AUTO_INCREMENT PRIMARY KEY,
   user_id INT NOT NULL,
   FOREIGN KEY(user_id) REFERENCES users(id));

3

@Andrewdotn'un işaret ettiği gibi en iyi yol, ayrıntılı hatayı görmektir (SHOW ENGINE INNODB STATUS; yalnızca bir hata kodu yerine ) .

Sebeplerden biri, aynı isimde bir dizinin zaten mevcut olması, başka bir tabloda olması olabilir. Pratik olarak, bu tür çakışmaları önlemek için tablo adının indeks adından önce önek olarak eklenmesini öneririm. örneğin idx_userIdkullanmak yerine idx_userActionMapping_userId.


3

Lütfen önce emin olun

  1. InnoDB tabloları kullanıyorsunuz.
  2. FOREIGN KEY alanı, kaynak alanla aynı tür ve uzunlukta (!).

Ben de aynı sorunu yaşadım ve düzelttim. Bir alan için INT işaretsiz ve diğer alan için sadece tamsayı vardı.


2

Faydalı ipucu, sorgunuzu SHOW WARNINGS;denedikten sonra CREATEkullanın ve hatayı ve daha ayrıntılı uyarıyı alacaksınız:

    ---------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                 |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+
| Warning |  150 | Create table 'fakeDatabase/exampleTable' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns.
|
| Error   | 1005 | Can't create table 'exampleTable' (errno:150)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

Yani bu durumda, masamı yeniden oluşturma zamanı!


1

Bu genellikle dosyayı mevcut veritabanına kaynak oluşturmaya çalıştığınızda olur. Önce tüm tabloları (veya DB'nin kendisini) bırakın. Ve sonra SET foreign_key_checks = 0;başında ve SET foreign_key_checks = 1;sonunda kaynak dosyası .


1

Bunun başarısız olmasının başka bir nedenini buldum ... büyük / küçük harfe duyarlı tablo adları.

Bu tablo tanımı için

CREATE TABLE user (
  userId int PRIMARY KEY AUTO_INCREMENT,
  username varchar(30) NOT NULL
) ENGINE=InnoDB;

Bu tablo tanımı çalışır

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES **u**ser(userId)
) ENGINE=InnoDB;

oysa bu başarısız olur

CREATE TABLE product (
  id int PRIMARY KEY AUTO_INCREMENT,
  userId int,
  FOREIGN KEY fkProductUser1(userId) REFERENCES User(userId)
) ENGINE=InnoDB;

Windows'ta çalışması ve Unix'te başarısız olması gerçeği anlamam birkaç saatimi aldı. Umarım bu başka birine yardımcı olur.


1

Mac OS için MySQL Workbench 6.3.

Sorun: DB diyagramında İleri Mühendislik yapmaya çalışırken tablo X üzerinde hata no 150, 21'den 20'si başarılı, 1'i başarısız oldu. Tablo X üzerindeki FK'ler silinmişse, hata daha önce başarısız olmayan farklı bir tabloya taşınır.

Tüm tablolar motoru myISAM olarak değiştirildi ve gayet iyi çalıştı.

görüntü açıklamasını buraya girin


0

Ayrıca yanlışlıkla yanlış veritabanında çalışmadığınızı kontrol etmeye değer. Bu hata, yabancı tablo yoksa ortaya çıkar. MySQL neden bu kadar şifreli olmak zorunda?


0

Yabancı anahtarların üstte benzersiz olarak listelenmediğinden emin olun. Ben de aynı sorunu yaşadım ve onu benzersiz değil olarak ayırarak çözdüm.


0

Benim durumumda, yabancı anahtar alanı olan alanın çok uzun bir isme sahip olmasından kaynaklanıyordu, yani. foreign key (some_other_table_with_long_name_id). Daha kısa deneyin. Bu durumda hata mesajı biraz yanıltıcıdır.

Ayrıca, @Jon'un daha önce de bahsettiği gibi - alan tanımlarının aynı olması gerekir ( unsignedalt türe dikkat edin ).


0

(Yan notlar Yorum için çok büyük)

AUTO_INCREMENTBir eşleme tablosunda bir id'ye gerek yoktur ; ondan kurtulmak.

Değişim PRIMARY KEYiçin (role_id, role_group_id)(ya düzen içinde). Bu, erişimi hızlandıracaktır.

Muhtemelen her iki yönü de eşleştirmek istediğinizden, INDEXbu iki sütunu ters sırada da ekleyin . (Yapmaya gerek yok UNIQUE.)

Daha fazla ipucu: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta



0

tablo oluşturmadan önce aşağıdaki satırı çalıştırın: SET FOREIGN_KEY_CHECKS = 0;

FOREIGN_KEY_CHECKS seçeneği, InnoDB tabloları için yabancı anahtar kısıtlamalarının kontrol edilip edilmeyeceğini belirtir.

- Yabancı anahtar kısıtlamalarını kontrol etmeyi belirtin (bu varsayılandır)

SET FOREIGN_KEY_CHECKS = 1;

 

- Yabancı anahtar kısıtlamalarını kontrol etmeyin

FOREIGN_KEY_CHECKS = 0;

Ne Zaman Kullanılmalı: Bilgi kısıtlamalarını geçici olarak devre dışı bırakmak (FOREIGN_KEY_CHECKS'i 0 olarak ayarlayın), tabloları yeniden oluşturmanız ve herhangi bir üst-alt sırada veri yüklemeniz gerektiğinde kullanışlıdır


-1

Ben de aynı sorunla karşılaştım, ancak ana tabloya sahip olmadığımı kontrol ettim. Bu yüzden sadece çocuk göçünün önünde ebeveyn geçişini düzenliyorum. Sadece yap.


1
bu bir cevap yerine bir yorum
olmalıydı
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.