MySQL การสร้างตารางด้วยคีย์ต่างประเทศให้ errno: 150


98

ฉันกำลังพยายามสร้างตารางใน MySQL ด้วยคีย์ต่างประเทศสองคีย์ซึ่งอ้างอิงคีย์หลักในอีก 2 ตาราง แต่ฉันได้รับข้อผิดพลาด errno: 150 และจะไม่สร้างตาราง

นี่คือ SQL สำหรับทั้ง 3 ตาราง:

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;

ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก.


1
คุณช่วยโพสต์ผลลัพธ์ข้อผิดพลาดและแจ้งให้เราทราบได้ไหมว่าคำสั่งใด (จากสามข้อ) ที่ทำให้เกิดข้อผิดพลาด
dave

4
มีอะไรกลับเห็บอยู่รอบ ๆauto_increment? ไม่ถูกต้อง Auto_increment คือคีย์เวิร์ดไม่ใช่ตัวระบุ
Bill Karwin

คำตอบ:


240

ฉันมีปัญหาเดียวกันกับALTER TABLE ADD FOREIGN KEY.

หลังจากผ่านไปหนึ่งชั่วโมงฉันพบว่าต้องปฏิบัติตามเงื่อนไขเหล่านี้เพื่อไม่ให้เกิดข้อผิดพลาด 150:

  1. ตารางหลักต้องมีอยู่ก่อนที่คุณจะกำหนดคีย์นอกเพื่ออ้างอิง คุณต้องกำหนดตารางตามลำดับที่ถูกต้อง: ตารางหลักก่อนจากนั้นตารางลูก หากทั้งสองอ้างอิงตารางแต่ละอื่น ๆ คุณต้องสร้างตารางโดยไม่ จำกัด FK แล้วสร้างตารางที่สองแล้วเพิ่มข้อ จำกัด ในการ FK ALTER TABLEตารางแรกกับ

  2. สองตารางต้องสนับสนุนข้อ จำกัด ENGINE=InnoDBที่สำคัญต่างประเทศเช่น เอ็นจินหน่วยเก็บข้อมูลอื่น ๆ จะเพิกเฉยต่อคำจำกัดความของคีย์ต่างประเทศดังนั้นจึงไม่มีข้อผิดพลาดหรือคำเตือนกลับมา แต่จะไม่บันทึกข้อ จำกัด FK

  3. คอลัมน์ที่อ้างอิงในตารางหลักต้องเป็นคอลัมน์ทางซ้ายสุดของคีย์ ที่ดีที่สุดถ้าสำคัญในการปกครองที่เป็นหรือPRIMARY KEYUNIQUE KEY

  4. คำจำกัดความ FK ต้องอ้างอิงคอลัมน์ PK ตามลำดับเดียวกันกับนิยาม PK ตัวอย่างเช่นถ้า FK REFERENCES Parent(a,b,c)แล้ว PK (a,c,b)ผู้ปกครองจะต้องไม่ถูกกำหนดไว้ในคอลัมน์ในการสั่งซื้อ

  5. คอลัมน์ PK ในตารางหลักต้องเป็นประเภทข้อมูลเดียวกับคอลัมน์ FK ในตารางลูก ตัวอย่างเช่นหากคอลัมน์ PK ในตารางหลักคือUNSIGNEDต้องแน่ใจว่าได้กำหนดUNSIGNEDสำหรับคอลัมน์ที่เกี่ยวข้องในฟิลด์ Child table

    ข้อยกเว้น: ความยาวของสตริงอาจแตกต่างกัน ตัวอย่างเช่นVARCHAR(10)สามารถอ้างอิงVARCHAR(20)หรือในทางกลับกัน

  6. คอลัมน์ FK ประเภทสตริงใด ๆ ต้องมีชุดอักขระและการเรียงลำดับเดียวกันกับคอลัมน์ PK ที่เกี่ยวข้อง

  7. หากมีข้อมูลอยู่ในตาราง Child แล้วทุกค่าในคอลัมน์ FK จะต้องตรงกับค่าในคอลัมน์ PK ของตารางหลัก ตรวจสอบสิ่งนี้ด้วยแบบสอบถามเช่น:

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

    สิ่งนี้จะต้องส่งคืนค่าที่ไม่ตรงกันเป็นศูนย์ (0) เห็นได้ชัดว่าแบบสอบถามนี้เป็นตัวอย่างทั่วไป คุณต้องแทนที่ชื่อตารางและชื่อคอลัมน์ของคุณ

  8. ตารางหลักหรือตารางย่อยไม่สามารถเป็นTEMPORARYตารางได้

  9. ตารางหลักหรือตารางย่อยไม่สามารถเป็นPARTITIONEDตารางได้

  10. หากคุณประกาศ FK พร้อมON DELETE SET NULLตัวเลือกคอลัมน์ FK จะต้องเป็นโมฆะ

  11. หากคุณประกาศชื่อข้อ จำกัด สำหรับคีย์นอกชื่อข้อ จำกัด ต้องไม่ซ้ำกันในสคีมาทั้งหมดไม่เพียง แต่ในตารางที่มีการกำหนดข้อ จำกัด เท่านั้น ตารางสองตารางอาจไม่มีข้อ จำกัด ของตัวเองที่มีชื่อเดียวกัน

  12. หากมี FK อื่น ๆ ในตารางอื่นที่ชี้ไปที่ฟิลด์เดียวกันที่คุณกำลังพยายามสร้าง FK ใหม่และมีรูปแบบไม่ถูกต้อง (เช่นการเรียงลำดับที่แตกต่างกัน) พวกเขาจะต้องทำให้สอดคล้องกันก่อน นี่อาจเป็นผลมาจากการเปลี่ยนแปลงในอดีตซึ่งSET FOREIGN_KEY_CHECKS = 0;ถูกนำไปใช้กับความสัมพันธ์ที่ไม่สอดคล้องกันซึ่งกำหนดโดยไม่ได้ตั้งใจ ดูคำตอบของ @ andrewdotn ด้านล่างสำหรับคำแนะนำในการระบุปัญหา FK เหล่านี้

หวังว่านี่จะช่วยได้


4
สิ่งที่ควรเพิ่มอีกอย่างหนึ่ง: หาก PK ของตารางพาเรนต์มีมากกว่าหนึ่งฟิลด์ลำดับของฟิลด์ใน FK จะต้องเหมือนกับลำดับใน PK
Kip

26
ซึ่งรวมถึงสิ่งที่ต้องการVSint(11) unsigned NOT NULL int(11) NOT NULL
Glen Solsberry

4
แก้ไขตาราง table_name ENGINE = InnoDB;
TolMera

12
ถ้าตารางถูกกำหนด ENGINE = MyISAM จะไม่สร้าง errno 150 เนื่องจากไม่สนใจการประกาศคีย์ต่างประเทศ เหมือนกับการบอกว่าวิธีที่ดีที่สุดในการหลีกเลี่ยงปัญหาเกี่ยวกับเครื่องยนต์ของรถยนต์คือการขับเรือ :-)
Bill Karwin

2
นอกจากนี้หากON DELETEกฎCONSTRAINT ของคุณSET NULLตรวจสอบให้แน่ใจว่าคีย์นอกนั้นสามารถเป็นโมฆะได้จริง! ฉันใช้เวลา 30 นาทีในการอ่านคำตอบนี้ซ้ำแล้วซ้ำเล่าเพื่อให้แน่ใจว่าตารางของฉันตรงตามเงื่อนไข แต่ยังคงได้รับ Error 150 จากนั้นฉันสังเกตว่า FK ของฉันเป็นฟิลด์ NOT NULL ซึ่งหมายความว่ากฎนั้นไม่สามารถนำไปใช้ได้
Martin Joiner

62

ข้อความ "errno 150" ทั่วไปของ MySQL หมายความว่ามีการสร้างข้อ จำกัด ของคีย์ต่างประเทศไม่ถูกต้อง " ดังที่คุณทราบอยู่แล้วว่าคุณกำลังอ่านหน้านี้ข้อความแสดงข้อผิดพลาด“ errno: 150” ทั่วไปนั้นไม่เป็นประโยชน์ อย่างไรก็ตาม:

คุณสามารถรับข้อความแสดงข้อผิดพลาดจริงได้โดยเรียกใช้SHOW ENGINE INNODB STATUS;จากนั้นค้นหาLATEST FOREIGN KEY ERRORในผลลัพธ์

ตัวอย่างเช่นการพยายามสร้างข้อ จำกัด ของคีย์ต่างประเทศ:

CREATE TABLE t1
(id INTEGER);

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

Can't create table 'test.t2' (errno: 150)ล้มเหลวด้วยข้อผิดพลาด นั่นไม่ได้บอกอะไรที่เป็นประโยชน์กับใครเลยนอกจากนั้นมันเป็นปัญหาคีย์ต่างประเทศ แต่เรียกใช้SHOW ENGINE INNODB STATUS;และมันจะพูดว่า:

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

มันบอกว่าปัญหามันหาดัชนีไม่ได้ SHOW INDEX FROM t1แสดงให้เห็นว่ามีไม่ดัชนีใด ๆ t1เลยสำหรับตาราง แก้ไขโดยพูดกำหนดคีย์หลักบนt1และข้อ จำกัด ของคีย์ภายนอกจะถูกสร้างขึ้นสำเร็จ


4
SHOW ENGINE INNODB STATUSช่วยให้ฉันระบุปัญหาได้ทันทีที่ฉันพยายามวินิจฉัยมาเกือบหนึ่งชั่วโมง ขอบคุณ.
jatrim

ในกรณีของฉันสิ่งนี้ชี้ให้เห็นว่าตารางที่แตกต่างกันโดยสิ้นเชิงที่ FK เป็นฟิลด์เดียวกันกับที่ฉันพยายามชี้ไปนั้นไม่สอดคล้องกันและจะไม่บันทึกตารางใหม่ ... โดยสมมติว่านี่มาจากการใช้SET FOREIGN_KEY_CHECKS = 0;ระหว่างการนำเข้า / การเปลี่ยนแปลงที่ผิดรูปแบบ ครั้งเดียวหรืออีกครั้ง ขอบคุณมาก
oucil

25

ตรวจสอบให้แน่ใจว่าคุณสมบัติของสองฟิลด์ที่คุณพยายามเชื่อมโยงกับข้อ จำกัด นั้นเหมือนกันทุกประการ

บ่อยครั้งคุณสมบัติที่ 'ไม่ได้ลงนาม' ในคอลัมน์ ID จะดึงดูดคุณออกไป

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

จากประสบการณ์ของฉันมันคุ้มค่าที่จะใช้ SHOW CREATE TABLE ของ MySQL บนตารางหลักของคุณเพื่อตรวจสอบว่าแฟล็กใดที่ตั้งค่ากับคอลัมน์ดัชนีหลักของคุณจากนั้นคัดลอกไปยังคอลัมน์คีย์ต่างประเทศของคุณ อาจมีบางอย่างเช่น "ไม่ได้ลงนาม" ที่ไม่ชัดเจน
Ambulare

10

สถานะปัจจุบันของฐานข้อมูลของคุณเป็นอย่างไรเมื่อคุณเรียกใช้สคริปต์นี้ มันว่างเปล่า? SQL ของคุณทำงานได้ดีสำหรับฉันเมื่อสร้างฐานข้อมูลตั้งแต่เริ่มต้น แต่โดยปกติแล้ว errno 150 จะเกี่ยวข้องกับการวางและสร้างตารางที่เป็นส่วนหนึ่งของคีย์ต่างประเทศ ฉันรู้สึกว่าคุณไม่ได้ทำงานกับฐานข้อมูลใหม่และใหม่ 100%

หากคุณพบข้อผิดพลาดเมื่อ "source" - เปิดไฟล์ SQL ของคุณคุณควรจะสามารถเรียกใช้คำสั่ง "SHOW ENGINE INNODB STATUS" จากพรอมต์ MySQL ทันทีหลังคำสั่ง "source" เพื่อดูข้อมูลข้อผิดพลาดโดยละเอียดเพิ่มเติม

คุณอาจต้องการตรวจสอบรายการคู่มือด้วย:

หากคุณสร้างตารางใหม่ที่ถูกทิ้งตารางนั้นจะต้องมีคำจำกัดความที่สอดคล้องกับข้อ จำกัด ของ Foreign Key ที่อ้างถึง ต้องมีชื่อคอลัมน์และประเภทที่ถูกต้องและต้องมีดัชนีบนคีย์ที่อ้างอิงตามที่ระบุไว้ก่อนหน้านี้ หากสิ่งเหล่านี้ไม่เป็นที่พอใจ MySQL จะแสดงข้อผิดพลาดหมายเลข 1005 และอ้างถึงข้อผิดพลาด 150 ในข้อความแสดงข้อผิดพลาด หาก MySQL รายงานข้อผิดพลาดหมายเลข 1005 จากคำสั่ง CREATE TABLE และข้อความแสดงข้อผิดพลาดอ้างถึงข้อผิดพลาด 150 การสร้างตารางล้มเหลวเนื่องจากข้อ จำกัด ของคีย์ต่างประเทศไม่ได้ถูกสร้างขึ้นอย่างถูกต้อง

- MySQL คู่มือ


5

สำหรับผู้ที่ดูกระทู้นี้ด้วยปัญหาเดียวกัน:

มีหลายสาเหตุที่ทำให้เกิดข้อผิดพลาดเช่นนี้ สำหรับรายการสาเหตุและวิธีแก้ไขข้อผิดพลาดคีย์ต่างประเทศใน MySQL ที่ค่อนข้างสมบูรณ์ (รวมถึงที่กล่าวถึงที่นี่) โปรดดูที่ลิงค์นี้:

MySQL Foreign Key Errors และ Errno 150


4

สำหรับคนอื่น ๆ ที่พบรายการ SO นี้ผ่านทาง Google: ตรวจสอบให้แน่ใจว่าคุณไม่ได้พยายามดำเนินการ SET NULL ในคอลัมน์ Foreign Key (to be) ที่กำหนดเป็น "NOT NULL" นั่นทำให้ผมหงุดหงิดมากจนจำได้ว่าต้องทำ CHECK ENGINE INNODB STATUS


3

แน่นอนว่ามันไม่ใช่อย่างนั้น แต่ฉันพบว่าข้อผิดพลาดนี้เป็นเรื่องธรรมดาและไม่สามารถเปิดเผยได้ เป้าหมายของอาจจะไม่ได้FOREIGN KEY PRIMARY KEYคำตอบที่เป็นประโยชน์สำหรับฉันคือ:

คีย์ต่างประเทศจะต้องชี้ไปที่ฟิลด์จริงคีย์หลักของตารางอื่นเสมอ

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 ชี้วิธีที่ดีที่สุดคือดูข้อผิดพลาดโดยละเอียด (SHOW ENGINE INNODB STATUS; ) แทนที่จะเป็นเพียงรหัสข้อผิดพลาด

สาเหตุหนึ่งอาจเป็นเพราะดัชนีมีชื่อเดียวกันอยู่แล้วอาจอยู่ในตารางอื่น ตามหลักปฏิบัติฉันขอแนะนำให้ใส่คำนำหน้าชื่อตารางก่อนชื่อดัชนีเพื่อหลีกเลี่ยงการชนกันดังกล่าว เช่นแทนที่จะใช้idx_userIdidx_userActionMapping_userId


3

โปรดตรวจสอบในตอนแรกว่า

  1. คุณกำลังใช้ตาราง InnoDB
  2. ฟิลด์สำหรับคีย์ต่างประเทศมีประเภทและความยาว (!) เดียวกันกับฟิลด์ต้นทาง

ฉันมีปัญหาเดียวกันและได้แก้ไขแล้ว ฉันไม่ได้ลงนาม INT สำหรับหนึ่งฟิลด์และเป็นเพียงจำนวนเต็มสำหรับฟิลด์อื่น


2

เคล็ดลับที่เป็นประโยชน์ให้ใช้SHOW WARNINGS;หลังจากลองใช้CREATEแบบสอบถามของคุณแล้วคุณจะได้รับข้อผิดพลาดพร้อมทั้งคำเตือนโดยละเอียด:

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

ดังนั้นในกรณีนี้ได้เวลาสร้างตารางใหม่!


1

โดยปกติจะเกิดขึ้นเมื่อคุณพยายามซอร์สไฟล์ลงในฐานข้อมูลที่มีอยู่ วางตารางทั้งหมดก่อน (หรือฐานข้อมูลเอง) จากนั้นซอร์สไฟล์ด้วยSET foreign_key_checks = 0;ที่จุดเริ่มต้นและSET foreign_key_checks = 1;ตอนท้าย


1

ฉันพบเหตุผลอื่นที่ทำให้ล้มเหลว ...

สำหรับนิยามตารางนี้

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

นิยามตารางนี้ใช้ได้

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

ในขณะที่สิ่งนี้ล้มเหลว

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

ความจริงที่ว่ามันทำงานบน Windows และล้มเหลวใน Unix ทำให้ฉันต้องใช้เวลาสองสามชั่วโมงในการคิดออก หวังว่าจะช่วยคนอื่น


1

MySQL Workbench 6.3 สำหรับ Mac OS

ปัญหา: errno 150 บนตาราง X เมื่อพยายามทำ Forward Engineering บนแผนภาพ DB 20 จาก 21 สำเร็จ 1 รายการล้มเหลว ถ้า FK บนตาราง X ถูกลบข้อผิดพลาดจะย้ายไปยังตารางอื่นที่ไม่เคยล้มเหลวมาก่อน

เปลี่ยนเอ็นจินตารางทั้งหมดเป็น myISAM และทำงานได้ดี

ป้อนคำอธิบายภาพที่นี่


0

ควรตรวจสอบด้วยว่าคุณไม่ได้ใช้งานฐานข้อมูลผิดโดยไม่ได้ตั้งใจ ข้อผิดพลาดนี้จะเกิดขึ้นหากไม่มีตารางแปลกปลอม ทำไม MySQL จึงต้องมีความคลุมเครือ?


0

ตรวจสอบให้แน่ใจว่าคีย์ต่างประเทศไม่ได้อยู่ในรายการที่ไม่ซ้ำกันในพาเรนต์ ฉันมีปัญหาเดียวกันนี้และฉันแก้ไขโดยการแบ่งเขตว่าไม่ซ้ำกัน


0

ในกรณีของฉันมันเกิดจากความจริงที่ว่าฟิลด์ที่เป็นฟิลด์คีย์ต่างประเทศมีชื่อยาวเกินไปเช่น foreign key (some_other_table_with_long_name_id). พยายามให้สั้นลง ข้อความแสดงข้อผิดพลาดทำให้เข้าใจผิดเล็กน้อยในกรณีนั้น

นอกจากนี้ตามที่ @Jon กล่าวไว้ก่อนหน้านี้ - คำจำกัดความของฟิลด์ต้องเหมือนกัน (ระวังunsignedประเภทย่อย)


0

(หมายเหตุด้านข้างใหญ่เกินไปสำหรับความคิดเห็น)

ไม่จำเป็นต้องมีAUTO_INCREMENTid ในตารางการแมป กำจัดมัน.

เปลี่ยนPRIMARY KEYไป(role_id, role_group_id)(ในการสั่งซื้ออย่างใดอย่างหนึ่ง) ซึ่งจะทำให้การเข้าถึงเร็วขึ้น

เนื่องจากคุณอาจต้องการแมปทั้งสองทิศทางให้เพิ่มINDEXคอลัมน์ด้วยสองคอลัมน์นี้ในลำดับตรงข้ามกัน (ไม่จำเป็นต้องทำUNIQUE)

เคล็ดลับเพิ่มเติม: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta



0

ดำเนินการบรรทัดด้านล่างก่อนสร้างตาราง: SET FOREIGN_KEY_CHECKS = 0;

อ็อพชัน FOREIGN_KEY_CHECKS ระบุว่าจะตรวจสอบข้อ จำกัด คีย์ต่างประเทศสำหรับตาราง InnoDB หรือไม่

- ระบุเพื่อตรวจสอบข้อ จำกัด ของคีย์ต่างประเทศ (นี่คือค่าเริ่มต้น)

SET FOREIGN_KEY_CHECKS = 1;

 

- อย่าตรวจสอบข้อ จำกัด ของคีย์ต่างประเทศ

ตั้งค่า FOREIGN_KEY_CHECKS = 0;

ควรใช้เมื่อใด: การปิดใช้งานข้อ จำกัด การอ้างอิงชั่วคราว (ตั้งค่า FOREIGN_KEY_CHECKS เป็น 0) มีประโยชน์เมื่อคุณต้องการสร้างตารางใหม่และโหลดข้อมูลตามลำดับแม่ลูก


-1

ฉันพบปัญหาเดียวกัน แต่ฉันตรวจสอบพบว่าฉันไม่มีตารางหลัก ดังนั้นฉันจึงแก้ไขการย้ายข้อมูลระดับบนหน้าของการย้ายข้อมูลลูก แค่ทำมัน.


1
สิ่งนี้ควรเป็นความคิดเห็นแทนคำตอบ
hannad rehman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.