MySQL Membuat tabel dengan Foreign Key memberikan errno: 150

98

Saya mencoba membuat tabel di MySQL dengan dua kunci asing, yang mereferensikan kunci utama di 2 tabel lainnya, tetapi saya mendapatkan kesalahan errno: 150 dan itu tidak akan membuat tabel.

Berikut adalah SQL untuk ketiga tabel tersebut:

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;

Bantuan apa pun akan sangat dihargai.

Bill Karwin
sumber
1
Bisakah Anda memposting keluaran kesalahan dan memberi tahu kami perintah mana (dari ketiganya) yang menyebabkan kesalahan?
Dave
4
Ada apa dengan kutu punggung auto_increment? Itu tidak valid. Auto_increment adalah kata kunci, bukan pengenal.
Bill Karwin

Jawaban:

238

Saya memiliki masalah yang sama dengan ALTER TABLE ADD FOREIGN KEY.

Setelah satu jam, saya menemukan bahwa kondisi ini harus dipenuhi agar tidak mendapatkan kesalahan 150:

  1. Tabel Induk harus ada sebelum Anda menentukan kunci asing sebagai referensi. Anda harus menentukan tabel dalam urutan yang benar: Tabel induk terlebih dahulu, lalu tabel Anak. Jika kedua tabel mereferensikan satu sama lain, Anda harus membuat satu tabel tanpa batasan FK, lalu membuat tabel kedua, lalu menambahkan batasan FK ke tabel pertama dengan ALTER TABLE.

  2. Kedua tabel tersebut harus mendukung batasan kunci asing, yaitu ENGINE=InnoDB. Mesin penyimpanan lain diam-diam mengabaikan definisi kunci asing, sehingga tidak ada kesalahan atau peringatan, tetapi batasan FK tidak disimpan.

  3. Kolom yang direferensikan di tabel Induk harus merupakan kolom paling kiri dari sebuah kunci. Paling baik jika kunci di Induk adalah PRIMARY KEYatau UNIQUE KEY.

  4. Definisi FK harus mengacu pada kolom PK dalam urutan yang sama dengan definisi PK. Misalnya, jika FK REFERENCES Parent(a,b,c)maka PK Induk tidak boleh ditentukan pada kolom secara berurutan (a,c,b).

  5. Kolom PK di tabel Induk harus memiliki tipe data yang sama dengan kolom FK di tabel Anak. Misalnya, jika kolom PK di tabel Induk UNSIGNED, pastikan untuk menentukan UNSIGNEDuntuk kolom terkait di bidang tabel Anak.

    Pengecualian: panjang string mungkin berbeda. Misalnya VARCHAR(10)bisa referensi VARCHAR(20)atau sebaliknya.

  6. Kolom FK tipe string apa pun harus memiliki kumpulan karakter dan pemeriksaan yang sama dengan kolom PK yang sesuai.

  7. Jika sudah ada data di tabel Anak, setiap nilai di kolom FK harus sesuai dengan nilai di kolom PK tabel Induk. Periksa ini dengan pertanyaan seperti:

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

    Ini harus mengembalikan nol (0) nilai yang tidak cocok. Jelas, kueri ini adalah contoh umum; Anda harus mengganti nama tabel dan nama kolom Anda.

  8. Baik tabel Parent maupun tabel Child dapat berupa TEMPORARYtabel.

  9. Baik tabel Parent maupun tabel Child dapat berupa PARTITIONEDtabel.

  10. Jika Anda mendeklarasikan FK dengan ON DELETE SET NULLopsi, maka kolom FK harus nihil.

  11. Jika Anda mendeklarasikan nama batasan untuk kunci asing, nama batasan harus unik di seluruh skema, tidak hanya dalam tabel tempat batasan ditentukan. Dua tabel mungkin tidak memiliki batasannya sendiri dengan nama yang sama.

  12. Jika ada FK lain di tabel lain yang menunjuk ke bidang yang sama tempat Anda mencoba membuat FK baru, dan format tersebut salah (mis. Susunan berbeda), mereka harus dibuat konsisten terlebih dahulu. Ini mungkin hasil dari perubahan masa lalu di manaSET FOREIGN_KEY_CHECKS = 0; yang digunakan dengan hubungan yang tidak konsisten yang didefinisikan secara tidak sengaja. Lihat jawaban @ andrewdotn di bawah untuk instruksi bagaimana mengidentifikasi masalah FK ini.

Semoga ini membantu.

keajaiban
sumber
4
satu hal lagi yang perlu ditambahkan: jika PK tabel induk lebih dari satu field maka urutan field di FK harus sama dengan urutan pada PK
Kip
26
Ini termasuk hal-hal seperti int(11) unsigned NOT NULLvs int(11) NOT NULL.
Glen Solsberry
4
ALTER TABLE table_name ENGINE = InnoDB;
TolMera
12
Jika tabel didefinisikan ENGINE = MyISAM itu tidak menghasilkan errno 150 karena mengabaikan deklarasi kunci asing. Ini seperti mengatakan bahwa cara terbaik untuk menghindari masalah dengan mesin mobil Anda adalah dengan mengendarai perahu. :-)
Bill Karwin
2
Selain itu, jika ON DELETEaturan CONSTRAINT Anda adalah SET NULLpastikan kunci asing benar-benar NULL! Saya menghabiskan 30 menit membaca jawaban ini berulang-ulang, memastikan tabel saya memenuhi syarat tetapi masih mendapatkan Error 150. Kemudian saya perhatikan bahwa FK saya adalah bidang NOT NULL yang berarti aturan tersebut tidak mungkin diterapkan.
Martin Joiner
62

Pesan "errno 150" generik MySQL berarti bahwa batasan kunci asing tidak terbentuk dengan benar ." Seperti yang mungkin sudah Anda ketahui jika Anda membaca halaman ini, pesan kesalahan "errno: 150" generik benar-benar tidak membantu. Namun:

Anda bisa mendapatkan pesan kesalahan sebenarnya dengan menjalankan SHOW ENGINE INNODB STATUS;dan kemudian mencariLATEST FOREIGN KEY ERROR di keluaran.

Misalnya, upaya untuk membuat batasan kunci asing ini:

CREATE TABLE t1
(id INTEGER);

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

gagal dengan kesalahan Can't create table 'test.t2' (errno: 150). Itu tidak memberi tahu siapa pun yang berguna selain itu masalah kunci asing. Tapi lari SHOW ENGINE INNODB STATUS;dan itu akan berkata:

------------------------
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.

Ia mengatakan bahwa masalahnya adalah tidak dapat menemukan indeks. SHOW INDEX FROM t1menunjukkan bahwa tidak ada indeks sama sekali untuk tabel t1. Perbaiki dengan, katakanlah, mendefinisikan kunci utama pada t1, dan batasan kunci asing akan berhasil dibuat.

andrewdotn
sumber
4
SHOW ENGINE INNODB STATUSmembantu saya segera mengidentifikasi masalah yang telah saya coba diagnosis selama hampir satu jam. Terima kasih.
jatrim
Dalam kasus saya, ini menunjukkan bahwa tabel yang sama sekali berbeda yang memiliki FK pada bidang yang sama yang saya coba tunjukkan tidak konsisten dan karenanya tidak akan menyimpan yang baru ... dengan asumsi ini berasal dari penggunaan SET FOREIGN_KEY_CHECKS = 0;selama impor / perubahan yang salah format pada satu waktu atau lainnya. Bantuan besar, terima kasih.
oucil
25

Pastikan properti dari dua kolom yang Anda coba tautkan dengan batasan sama persis.

Seringkali, properti 'unsigned' di kolom ID akan menarik perhatian Anda.

ALTER TABLE `dbname`.`tablename` CHANGE `fieldname` `fieldname` int(10) UNSIGNED NULL;
Jon Winstanley
sumber
Dalam pengalaman saya, ada baiknya menggunakan SHOW CREATE TABLE MySQL di tabel utama Anda untuk memeriksa dengan tepat flag apa yang disetel terhadap kolom indeks utama Anda, lalu salin ke kolom kunci asing Anda. Mungkin ada hal-hal di sana, seperti "unsigned" yang tidak jelas.
Ambulare
10

Apa status database Anda saat ini ketika Anda menjalankan skrip ini? Apakah itu benar-benar kosong? SQL Anda berjalan dengan baik untuk saya saat membuat database dari awal, tetapi errno 150 biasanya berkaitan dengan menjatuhkan & membuat ulang tabel yang merupakan bagian dari kunci asing. Saya merasa Anda tidak bekerja dengan database yang 100% segar dan baru.

Jika Anda error saat "source" -ing file SQL Anda, Anda harus dapat menjalankan perintah "SHOW ENGINE INNODB STATUS" dari prompt MySQL segera setelah perintah "source" untuk melihat info kesalahan yang lebih rinci.

Anda mungkin ingin melihat entri manual juga:

Jika Anda membuat ulang tabel yang dihapus, itu harus memiliki definisi yang sesuai dengan batasan kunci asing yang mereferensikannya. Ini harus memiliki nama dan jenis kolom yang tepat, dan harus memiliki indeks pada kunci yang direferensikan, seperti yang dinyatakan sebelumnya. Jika ini tidak terpenuhi, MySQL mengembalikan nomor kesalahan 1005 dan merujuk ke kesalahan 150 dalam pesan kesalahan. Jika MySQL melaporkan nomor kesalahan 1005 dari pernyataan CREATE TABLE, dan pesan kesalahan mengacu pada kesalahan 150, pembuatan tabel gagal karena batasan kunci asing tidak terbentuk dengan benar.

- Manual referensi MySQL 5.1 .

Brent Menulis Kode
sumber
5

Untuk orang yang melihat utas ini dengan masalah yang sama:

Ada banyak alasan untuk mendapatkan error seperti ini. Untuk daftar penyebab dan solusi kesalahan kunci asing yang cukup lengkap di MySQL (termasuk yang dibahas di sini), lihat tautan ini:

Kesalahan MySQL Foreign Key dan Errno 150

juacala.dll
sumber
4

Untuk orang lain yang menemukan entri SO ini melalui Google: Pastikan Anda tidak mencoba melakukan tindakan SET NULL pada kolom kunci asing (menjadi) yang didefinisikan sebagai "NOT NULL." Itu menyebabkan frustrasi besar sampai saya ingat untuk melakukan PERIKSA STATUS INNODB MESIN.

Eric L.
sumber
3

Jelas bukan itu masalahnya tetapi saya menemukan kesalahan ini cukup umum dan tidak jelas. Target dari sebuah FOREIGN KEYtidak mungkin PRIMARY KEY. Jawaban yang bermanfaat bagi saya adalah:

KUNCI ASING selalu harus diarahkan ke bidang benar PRIMARY KEY dari tabel lain.

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));
I159
sumber
3

Seperti yang ditunjukkan oleh @andrewdotn, cara terbaik adalah melihat kesalahan mendetail ( SHOW ENGINE INNODB STATUS;), bukan hanya kode kesalahan.

Salah satu alasannya bisa jadi indeks sudah ada dengan nama yang sama, mungkin ada di tabel lain. Sebagai praktik, saya merekomendasikan memberi awalan nama tabel sebelum nama indeks untuk menghindari benturan seperti itu. misalnya alih-alih idx_userIddigunakan idx_userActionMapping_userId.

Lebih banyak
sumber
3

Harap pastikan pada awalnya

  1. Anda menggunakan tabel InnoDB.
  2. field untuk FOREIGN KEY memiliki jenis dan panjang (!) yang sama dengan field sumber.

Saya mengalami masalah yang sama dan saya telah memperbaikinya. Saya memiliki INT unsigned untuk satu bidang dan hanya integer untuk bidang lainnya.

Juljan
sumber
2

Tip bermanfaat, gunakan SHOW WARNINGS;setelah mencoba CREATEkueri Anda dan Anda akan menerima kesalahan serta peringatan yang lebih rinci:

    ---------------------------------------------------------------------------------------------------------+
| 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)                                                                                                                                                                           |
+---------+------+--------------------------------------------------------------------------                          --------------------------------------------------------------------------------------------                          ---------------+

Jadi dalam hal ini, saatnya membuat ulang tabel saya!

sturrockad
sumber
1

Ini biasanya terjadi ketika Anda mencoba untuk memasukkan file ke database yang sudah ada. Jatuhkan semua tabel terlebih dahulu (atau DB itu sendiri). Dan kemudian file sumber dengan SET foreign_key_checks = 0;di awal dan SET foreign_key_checks = 1;di akhir.

wholenewstrain
sumber
1

Saya telah menemukan alasan lain ini gagal ... nama tabel case sensitive.

Untuk definisi tabel ini

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

Definisi tabel ini berfungsi

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

sedangkan yang ini gagal

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

Fakta bahwa itu bekerja di Windows dan gagal di Unix membutuhkan beberapa jam untuk saya mengetahuinya. Harapan yang membantu orang lain.

Tim
sumber
1

MySQL Workbench 6.3 untuk Mac OS.

Masalah: errno 150 pada tabel X ketika mencoba melakukan Teknik Maju pada diagram DB, 20 dari 21 berhasil, 1 gagal. Jika FK di tabel X dihapus, kesalahan dipindahkan ke tabel lain yang sebelumnya tidak gagal.

Mengubah semua mesin tabel ke myISAM dan berfungsi dengan baik.

masukkan deskripsi gambar di sini

Eduardo Chongkan
sumber
0

Juga perlu diperiksa bahwa Anda tidak beroperasi pada database yang salah. Kesalahan ini akan terjadi jika tabel asing tidak ada. Mengapa MySQL harus begitu samar?

SystemParadox
sumber
0

Pastikan bahwa kunci asing tidak terdaftar sebagai unik di induk. Saya memiliki masalah yang sama dan saya menyelesaikannya dengan membatasi sebagai tidak unik.

Raza
sumber
0

Dalam kasus saya, itu karena fakta bahwa field yang merupakan field kunci asing memiliki nama yang terlalu panjang, yaitu. foreign key (some_other_table_with_long_name_id). Coba lebih pendek. Pesan kesalahan agak menyesatkan dalam kasus itu.

Selain itu, seperti yang disebutkan @Jon sebelumnya - definisi kolom harus sama (hati-hati dengan unsignedsubtipe).

Kangur
sumber
0

(Catatan sampingan terlalu besar untuk sebuah Komentar)

Tidak perlu AUTO_INCREMENTid dalam tabel pemetaan; singkirkan itu.

Ubah PRIMARY KEYmenjadi (role_id, role_group_id)(dalam urutan apa pun). Ini akan membuat akses lebih cepat.

Karena Anda mungkin ingin memetakan kedua arah, tambahkan juga INDEXdengan kedua kolom tersebut dalam urutan yang berlawanan. (Tidak perlu membuatnya UNIQUE.)

Kiat lainnya: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta

Rick James
sumber
0

Ketika batasan kunci asing didasarkan pada varcharjenis, maka di samping daftar yang disediakan olehmarv-el para kolom target harus memiliki kendala unik.

Muntah
sumber
0

jalankan baris di bawah ini sebelum membuat tabel: SET FOREIGN_KEY_CHECKS = 0;

Opsi FOREIGN_KEY_CHECKS menentukan apakah akan memeriksa batasan kunci asing untuk tabel InnoDB atau tidak.

- Tentukan untuk memeriksa batasan kunci asing (ini adalah default)

SET FOREIGN_KEY_CHECKS = 1;

 

- Jangan periksa kendala kunci asing

SETEL FOREIGN_KEY_CHECKS = 0;

Kapan Menggunakan: Menonaktifkan sementara batasan referensial (setel FOREIGN_KEY_CHECKS ke 0) berguna saat Anda perlu membuat ulang tabel dan memuat data dalam urutan induk-anak

pengguna11949964
sumber
-1

Saya mengalami masalah yang sama, tetapi saya memeriksa bahwa saya tidak memiliki tabel induk. Jadi saya hanya mengedit migrasi orang tua di depan migrasi anak. Lakukan saja.

韩向飞
sumber
1
ini seharusnya menjadi komentar, bukan jawaban
hannad rehman