MySQL Tạo bảng với các khóa ngoại cho errno: 150


98

Tôi đang cố gắng tạo một bảng trong MySQL với hai khóa ngoại, tham chiếu đến các khóa chính trong 2 bảng khác, nhưng tôi gặp lỗi errno: 150 và nó sẽ không tạo được bảng.

Đây là SQL cho cả 3 bảng:

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;

Mọi sự trợ giúp sẽ rất được trân trọng.


1
Bạn có thể đăng kết quả lỗi và cho chúng tôi biết lệnh nào (trong ba lệnh) gây ra lỗi không?
dave 21/09/09

4
Điều gì với những con ve xung quanh auto_increment? Điều đó không hợp lệ. Auto_increment là một từ khóa, không phải là một định danh.
Bill Karwin 21/09/09

Câu trả lời:


238

Tôi đã có cùng một vấn đề với ALTER TABLE ADD FOREIGN KEY.

Sau một giờ, tôi thấy rằng các điều kiện này phải được thỏa mãn để không gặp lỗi 150:

  1. Bảng Gốc phải tồn tại trước khi bạn xác định khóa ngoại để tham chiếu nó. Bạn phải xác định các bảng theo đúng thứ tự: Bảng cha đầu tiên, sau đó đến bảng Con. Nếu cả hai bảng tham chiếu lẫn nhau, bạn phải tạo một bảng không có ràng buộc FK, sau đó tạo bảng thứ hai, sau đó thêm ràng buộc FK vào bảng đầu tiên với ALTER TABLE.

  2. Cả hai bảng phải hỗ trợ các ràng buộc khóa ngoại, tức là ENGINE=InnoDB. Các công cụ lưu trữ khác âm thầm bỏ qua các định nghĩa khóa ngoại, do đó chúng không trả về lỗi hoặc cảnh báo nào, nhưng ràng buộc FK không được lưu.

  3. Các cột được tham chiếu trong bảng Gốc phải là cột ngoài cùng bên trái của một khóa. Tốt nhất nếu khóa trong Parent là PRIMARY KEYhoặc UNIQUE KEY.

  4. Định nghĩa FK phải tham chiếu đến (các) cột PK theo cùng thứ tự với định nghĩa PK. Ví dụ, nếu FK REFERENCES Parent(a,b,c)thì PK của cha mẹ không được xác định trên các cột theo thứ tự (a,c,b).

  5. (Các) cột PK trong bảng Gốc phải cùng kiểu dữ liệu với (các) cột FK trong bảng Con. Ví dụ: nếu là cột PK trong bảng Gốc UNSIGNED, hãy nhớ xác định UNSIGNEDcột tương ứng trong trường Bảng con.

    Ngoại lệ: độ dài của các chuỗi có thể khác nhau. Ví dụ, VARCHAR(10)có thể tham chiếu VARCHAR(20)hoặc ngược lại.

  6. Bất kỳ (các) cột FK kiểu chuỗi nào cũng phải có cùng bộ ký tự và đối chiếu với (các) cột PK tương ứng.

  7. Nếu đã có dữ liệu trong bảng Con, thì mọi giá trị trong (các) cột FK phải khớp với một giá trị trong (các) cột PK trong bảng Cha. Kiểm tra điều này với một truy vấn như:

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

    Điều này phải trả về không (0) giá trị không khớp. Rõ ràng, truy vấn này là một ví dụ chung chung; bạn phải thay thế tên bảng và tên cột của mình.

  8. Bảng Gốc và bảng Con đều không thể là một TEMPORARYbảng.

  9. Bảng Gốc và bảng Con đều không thể là một PARTITIONEDbảng.

  10. Nếu bạn khai báo một FK với ON DELETE SET NULLtùy chọn, thì (các) cột FK phải có giá trị rỗng.

  11. Nếu bạn khai báo tên ràng buộc cho khóa ngoại, tên ràng buộc phải là duy nhất trong toàn bộ lược đồ, không chỉ trong bảng mà ràng buộc được định nghĩa. Hai bảng có thể không có ràng buộc riêng với cùng tên.

  12. Nếu có bất kỳ FK nào khác trong các bảng khác trỏ vào cùng một trường mà bạn đang cố gắng tạo FK mới và chúng bị sai định dạng (tức là đối chiếu khác nhau), trước tiên chúng sẽ cần phải được thống nhất. Điều này có thể là kết quả của những thay đổi trong quá khứ SET FOREIGN_KEY_CHECKS = 0;được sử dụng với mối quan hệ không nhất quán được xác định do nhầm lẫn. Xem câu trả lời của @ andrewdotn bên dưới để biết hướng dẫn về cách xác định các vấn đề này của FK.

Hi vọng điêu nay co ich.


4
thêm một điều đáng nói thêm: nếu PK của bảng cha là nhiều hơn một lĩnh vực, thứ tự của các trường trong FK phải giống như thứ tự trong PK
Kip

26
Điều này bao gồm những thứ như int(11) unsigned NOT NULLvs int(11) NOT NULL.
Glen Solsberry

4
ALTER TABLE table_name ENGINE = InnoDB;
TolMera

12
Nếu bảng được định nghĩa ENGINE = MyISAM, nó không tạo ra lỗi 150 vì nó bỏ qua khai báo khóa ngoại. Nó giống như nói rằng cách tốt nhất để tránh rắc rối với động cơ ô tô của bạn là lái một chiếc thuyền. :-)
Bill Karwin

2
Ngoài ra, nếu ON DELETEquy tắc CONSTRAINT của bạn là SET NULLđảm bảo khóa ngoại thực sự có thể là NULL! Tôi đã dành 30 phút để đọc đi đọc lại câu trả lời này, đảm bảo rằng các bảng của tôi đáp ứng các điều kiện nhưng vẫn nhận được Lỗi 150. Sau đó, tôi nhận thấy FK của mình là trường KHÔNG ĐẦY ĐỦ nghĩa là không thể áp dụng quy tắc.
Martin Joiner

62

Thông báo chung chung "errno 150" của MySQL " có nghĩa là ràng buộc khóa ngoại không được hình thành chính xác ." Như bạn có thể đã biết nếu bạn đang đọc trang này, thông báo lỗi chung chung “errno: 150” thực sự không hữu ích. Tuy nhiên:

Bạn có thể nhận được thông báo lỗi thực tế bằng cách chạy SHOW ENGINE INNODB STATUS;và sau đó tìm kiếm LATEST FOREIGN KEY ERRORtrong đầu ra.

Ví dụ, nỗ lực này nhằm tạo ra một ràng buộc khóa ngoại:

CREATE TABLE t1
(id INTEGER);

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

không thành công với lỗi Can't create table 'test.t2' (errno: 150). Điều đó không cho ai biết bất cứ điều gì hữu ích ngoài việc đó là một vấn đề khóa ngoại. Nhưng chạy SHOW ENGINE INNODB STATUS;và nó sẽ nói:

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

Nó nói rằng vấn đề là nó không thể tìm thấy một chỉ mục. SHOW INDEX FROM t1cho thấy rằng không có bất kỳ chỉ mục nào cho bảng t1. Hãy khắc phục điều đó bằng cách xác định khóa chính trên t1và ràng buộc khóa ngoại sẽ được tạo thành công.


4
SHOW ENGINE INNODB STATUSđã giúp tôi xác định ngay một vấn đề mà tôi đã cố gắng chẩn đoán trong gần một giờ. Cảm ơn.
jatrim

Trong trường hợp của tôi, điều này chỉ ra rằng một bảng hoàn toàn khác mà FK đã điền vào cùng một trường mà tôi đang cố trỏ đến không nhất quán và do đó sẽ không lưu bảng mới ... giả sử rằng bảng này được sử dụng SET FOREIGN_KEY_CHECKS = 0;trong quá trình nhập / thay đổi bị sai định dạng lúc này hay lúc khác. Giúp đỡ rất nhiều, cảm ơn.
oucil

25

Đảm bảo rằng các thuộc tính của hai trường bạn đang cố gắng liên kết với một ràng buộc hoàn toàn giống nhau.

Thông thường, thuộc tính 'unsigned' trên cột ID sẽ khiến bạn không hiểu.

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

Theo kinh nghiệm của tôi, bạn nên sử dụng BẢNG TẠO HIỂN THỊ của MySQL trên bảng chính của bạn để kiểm tra chính xác những cờ nào được đặt so với cột chỉ mục chính của bạn, sau đó sao chép chúng vào cột khóa ngoại của bạn. Có thể có những thứ ở đó, chẳng hạn như "không dấu" không rõ ràng.
Ambulare

10

Trạng thái hiện tại của cơ sở dữ liệu của bạn khi bạn chạy tập lệnh này là gì? Nó hoàn toàn trống rỗng? SQL của bạn chạy tốt đối với tôi khi tạo cơ sở dữ liệu từ đầu, nhưng errno 150 thường liên quan đến việc giảm và tạo lại các bảng là một phần của khóa ngoại. Tôi có cảm giác rằng bạn đang không làm việc với một cơ sở dữ liệu hoàn toàn mới và mới 100%.

Nếu bạn gặp lỗi khi "nguồn" -ing tệp SQL của mình, bạn có thể chạy lệnh "SHOW ENGINE INNODB STATUS" từ dấu nhắc MySQL ngay sau lệnh "source" để xem thông tin lỗi chi tiết hơn.

Bạn cũng có thể muốn kiểm tra mục nhập thủ công:

Nếu bạn tạo lại một bảng đã bị loại bỏ, nó phải có một định nghĩa phù hợp với các ràng buộc khóa ngoại tham chiếu đến nó. Nó phải có tên và loại cột phù hợp, và nó phải có chỉ mục trên các khóa được tham chiếu, như đã nêu trước đó. Nếu những điều này không được thỏa mãn, MySQL trả về số lỗi 1005 và đề cập đến lỗi 150 trong thông báo lỗi. Nếu MySQL báo cáo số lỗi 1005 từ một câu lệnh CREATE TABLE và thông báo lỗi đề cập đến lỗi 150, thì việc tạo bảng không thành công vì một ràng buộc khóa ngoại không được tạo đúng cách.

- Tài liệu tham khảo MySQL 5.1 .


5

Đối với những người đang xem chuỗi này với cùng một vấn đề:

Có rất nhiều nguyên nhân dẫn đến lỗi như thế này. Để có danh sách khá đầy đủ các nguyên nhân và giải pháp của lỗi khóa ngoại trong MySQL (bao gồm cả những lỗi được thảo luận ở đây), hãy xem liên kết này:

Lỗi và lỗi khóa ngoại MySQL 150


4

Đối với những người khác tìm thấy mục nhập SO này qua Google: Hãy đảm bảo rằng bạn không cố gắng thực hiện hành động SET NULL trên cột khóa ngoại (được) được định nghĩa là "NOT NULL." Điều đó gây ra sự thất vọng lớn cho đến khi tôi nhớ thực hiện KIỂM TRA TRẠNG THÁI ĐỘNG CƠ INNODB.


3

Chắc chắn là không phải vậy nhưng tôi thấy lỗi này khá phổ biến và không thể tránh khỏi. Mục tiêu của a FOREIGN KEYkhông thể PRIMARY KEY. Câu trả lời trở nên hữu ích đối với tôi là:

Một KEY NGOẠI LỆ luôn phải được trỏ đến một trường true KEY CHÍNH của bảng khác.

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

Như được chỉ ra bởi @andrewdotn, cách tốt nhất là xem lỗi chi tiết ( SHOW ENGINE INNODB STATUS;) thay vì chỉ một mã lỗi.

Một trong những lý do có thể là một chỉ mục đã tồn tại với cùng tên, có thể nằm trong một bảng khác. Theo thông lệ, tôi khuyên bạn nên đặt tiền tố tên bảng trước tên chỉ mục để tránh những va chạm như vậy. ví dụ thay vì idx_userIdsử dụng idx_userActionMapping_userId.


3

Hãy chắc chắn rằng lúc đầu

  1. bạn đang sử dụng bảng InnoDB.
  2. trường FOREIGN KEY có cùng kiểu và độ dài (!) với trường nguồn.

Tôi đã gặp vấn đề tương tự và tôi đã sửa nó. Tôi đã bỏ dấu INT cho một trường và chỉ là số nguyên cho trường khác.


2

Mẹo hữu ích, hãy sử dụng SHOW WARNINGS;sau khi thử CREATEtruy vấn của bạn và bạn sẽ nhận được lỗi cũng như cảnh báo chi tiết hơn:

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

Vì vậy, trong trường hợp này, đã đến lúc tạo lại bảng của tôi!


1

Điều này thường xảy ra khi bạn cố gắng nguồn tệp vào cơ sở dữ liệu hiện có. Bỏ tất cả các bảng trước (hoặc chính DB). Và sau đó tập tin nguồn với SET foreign_key_checks = 0;ở đầu và SET foreign_key_checks = 1;ở cuối.


1

Tôi đã tìm thấy một lý do khác khiến việc này không thành công ... tên bảng phân biệt chữ hoa chữ thường.

Đối với định nghĩa bảng này

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

Định nghĩa bảng này hoạt động

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

trong khi cái này không thành công

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

Thực tế là nó hoạt động trên Windows và không thành công trên Unix khiến tôi mất vài giờ để tìm ra. Hy vọng rằng sẽ giúp một người khác.


1

MySQL Workbench 6.3 dành cho Mac OS.

Sự cố: lỗi 150 trên bảng X khi cố gắng thực hiện Kỹ thuật chuyển tiếp trên sơ đồ DB, 20 trong số 21 thành công, 1 không thành công. Nếu FK trên bảng X bị xóa, thì lỗi đã chuyển sang một bảng khác mà trước đó không bị lỗi.

Đã thay đổi tất cả công cụ bảng thành myISAM và nó hoạt động tốt.

nhập mô tả hình ảnh ở đây


0

Cũng đáng để kiểm tra rằng bạn không vô tình thao tác trên cơ sở dữ liệu sai. Lỗi này sẽ xảy ra nếu bảng ngoại không tồn tại. Tại sao MySQL phải khó hiểu như vậy?


0

Đảm bảo rằng các khóa ngoại không được liệt kê là duy nhất trong khóa chính. Tôi đã gặp vấn đề tương tự và tôi đã giải quyết nó bằng cách phân định nó không phải là duy nhất.


0

Trong trường hợp của tôi, đó là do trường là trường khóa ngoại có tên quá dài, tức là. foreign key (some_other_table_with_long_name_id). Hãy thử sth ngắn hơn. Thông báo lỗi là một chút sai lầm trong trường hợp đó.

Ngoài ra, như @Jon đã đề cập trước đó - các định nghĩa trường phải giống nhau (chú ý unsignedloại phụ).


0

(Ghi chú bên quá lớn cho một Nhận xét)

Không cần AUTO_INCREMENTid trong bảng ánh xạ; Gạt nó ra.

Thay đổi PRIMARY KEYthành (role_id, role_group_id)(theo một trong hai thứ tự). Điều này sẽ giúp truy cập nhanh hơn.

Vì bạn có thể muốn lập bản đồ cả hai hướng, hãy thêm dấu INDEXvới hai cột đó theo thứ tự ngược lại. (Không cần thiết phải làm UNIQUE.)

Các mẹo khác: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta



0

thực hiện dòng dưới đây trước khi tạo bảng: SET FOREIGN_KEY_CHECKS = 0;

Tùy chọn FOREIGN_KEY_CHECKS chỉ định có hay không kiểm tra các ràng buộc khóa ngoại cho các bảng InnoDB.

- Chỉ định để kiểm tra các ràng buộc khóa ngoại (đây là mặc định)

SET FOREIGN_KEY_CHECKS = 1;

 

- Không kiểm tra các ràng buộc khóa ngoại

SET FOREIGN_KEY_CHECKS = 0;

Khi nào sử dụng: Tạm thời vô hiệu hóa các ràng buộc tham chiếu (đặt FOREIGN_KEY_CHECKS thành 0) rất hữu ích khi bạn cần tạo lại bảng và tải dữ liệu theo bất kỳ thứ tự cha-con nào


-1

Tôi gặp phải vấn đề tương tự, nhưng tôi kiểm tra thấy rằng tôi không có bảng cha. Vì vậy, tôi chỉ chỉnh sửa phần di chuyển mẹ trước phần di chuyển con. Cứ làm đi.


1
này cần phải có được một lời nhận xét thay vì một câu trả lời
Rehman hannad
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.