Lỗi Mysql 1452 - Không thể thêm hoặc cập nhật hàng con: ràng buộc khóa ngoại không thành công


237

Tôi có một chút vấn đề lạ. Tôi đang cố gắng thêm một khóa ngoại vào một bảng tham chiếu đến một bảng khác, nhưng vì một số lý do không thành công. Với kiến ​​thức hạn hẹp của tôi về MySQL, điều duy nhất có thể nghi ngờ là có một khóa ngoại trên một bảng khác tham chiếu đến cái mà tôi đang cố gắng tham khảo.

Tôi đã thực hiện một SHOW CREATE TABLEtruy vấn trên cả hai bảng, sourcecodes_tagslà bảng có khóa ngoại,sourcecodes là bảng được tham chiếu.

CREATE TABLE `sourcecodes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) unsigned NOT NULL,
 `language_id` int(11) unsigned NOT NULL,
 `category_id` int(11) unsigned NOT NULL,
 `title` varchar(40) CHARACTER SET utf8 NOT NULL,
 `description` text CHARACTER SET utf8 NOT NULL,
 `views` int(11) unsigned NOT NULL,
 `downloads` int(11) unsigned NOT NULL,
 `time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 KEY `user_id` (`user_id`),
 KEY `language_id` (`language_id`),
 KEY `category_id` (`category_id`),
 CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

CREATE TABLE `sourcecodes_tags` (
 `sourcecode_id` int(11) unsigned NOT NULL,
 `tag_id` int(11) unsigned NOT NULL,
 KEY `sourcecode_id` (`sourcecode_id`),
 KEY `tag_id` (`tag_id`),
 CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Đây là mã tạo ra lỗi:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

2
bạn cũng có thể đăng lệnh chèn / cập nhật dẫn đến lỗi không?
Zed

64
bảng của bạn trống khi bạn thêm khóa ngoại này?
Zed

12
hãy thử chạy truy vấn này để xem liệu có bất kỳ sourcecode_id nào không phải là id thực không: CHỌN sourcecode_id TỪ sourcecodes_tags WHERE sourcecode_id KHÔNG IN (CHỌN id TỪ sourcecodes AS tmp);
Zed

11
Cảm ơn Zed, đó là vấn đề mà một trong các bảng có dữ liệu trong đó. Nghĩ về nó bây giờ nó có ý nghĩa rằng nó đã thất bại bởi vì có những thứ đang tham khảo các mặt hàng không tồn tại, nhưng tôi sẽ không bao giờ đoán được điều đó. Cảm ơn!
Zim

2
Tại sao nó thất bại nếu bảng trống?
theblackpearl

Câu trả lời:


226

Rất có thể sourcecodes_tagsbảng của bạn chứa sourcecode_idcác giá trị không còn tồn tại trong sourcecodesbảng của bạn . Bạn phải thoát khỏi những người đầu tiên.

Đây là một truy vấn có thể tìm thấy các ID đó:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;

UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)sẽ giúp thoát khỏi những ID đó. Hoặc nếu nullkhông được phép vào sourcecode_id, sau đó xóa các hàng đó hoặc thêm các giá trị bị thiếu đó vào sourcecodesbảng.
naXa

Tôi cũng nghĩ như vậy nhưng, đối với tôi SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULLkhông trả lại bất cứ điều gì, vì vậy vấn đề là ở nơi khác!?
Meloman

Ahh đây là vấn đề đối với tôi. Tôi đã cố chạy UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;, không liên quan đến khóa ngoại, vì vậy tôi đã bối rối. Nhưng thực tế là bảng liên lạc của tôi bị thiếu một số bản ghi mà bảng tự động được gọi là khiến nó ném "Mã lỗi: 1452. Không thể thêm hoặc cập nhật một hàng con: một ràng buộc khóa ngoại không thành công".
Ryan

99

Tôi có cùng một vấn đề với cơ sở dữ liệu MySQL của tôi nhưng cuối cùng, tôi đã có một giải pháp hiệu quả với tôi.
Vì trong bảng của tôi, mọi thứ đều ổn theo quan điểm mysql (cả hai bảng nên sử dụng công cụ InnoDB và kiểu dữ liệu của mỗi cột phải cùng loại tham gia ràng buộc khóa ngoài).
Điều duy nhất tôi đã làm là vô hiệu hóa kiểm tra khóa ngoại và sau đó bật nó sau khi thực hiện thao tác khóa ngoại.
Các bước tôi đã thực hiện:

SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8  Duplicates: 0  Warnings: 0
SET foreign_key_checks = 1;

49
Foreign_key_checks ở đó vì một lý do. Nếu bạn không thể thêm khóa ngoại vì nó vi phạm ràng buộc, bạn nên sửa dữ liệu trước. Tắt kiểm tra sau đó thêm khóa khiến bạn rơi vào trạng thái không nhất quán. Kiểm tra khóa ngoài thêm chi phí, nếu bạn không muốn sử dụng chúng, thì hãy sử dụng myisam thay thế.
cs_alumnus

5
@AbuSadatMohammedYasin không nên: câu hỏi hỏi "chuyện gì đang xảy ra" và câu trả lời này đơn giản là không cố gắng giải thích nó. Như cs_alumnus đã đề cập, có một vấn đề lớn hơn: tất cả các giá trị mới nên tham chiếu một giá trị khác trong bảng khác (như một khóa ngoại nên làm) có thể chỉ ra không có gì, tạo ra trạng thái không nhất quán. Giải thích ngắn gọn và hiệu quả của Cayetano cho phép bạn tìm ra những giá trị nào bạn nên cập nhật trước khi tạo ràng buộc để bạn không bị bất ngờ bởi các truy vấn sẽ trả về các giá trị nên tồn tại!
Armfoot

55

Sử dụng NOT INđể tìm nơi ràng buộc bị ràng buộc :

SELECT column FROM table WHERE column NOT IN 
(SELECT intended_foreign_key FROM another_table)

vì vậy, cụ thể hơn:

SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN 
(SELECT id FROM sourcecodes)

EDIT: INvà các NOT INtoán tử được biết là nhanh hơn nhiều so với các JOINtoán tử, cũng như dễ dàng hơn để xây dựng và lặp lại.


1
Vì vậy, nếu tôi hiểu điều này một cách chính xác, chúng ta có thể thêm khóa ngoại vào bảng đã có dữ liệu trong đó, nhưng chỉ khi một hàng con tồn tại cho mỗi hàng trong bảng cha? Nếu không có hàng con cho mỗi hàng trong bảng cha (đó là những gì truy vấn của bạn phát hiện ra) thì tập lệnh khóa ngoài sẽ thất bại.
Vincent

@Vincent nếu theo bảng cha bạn có nghĩa là bảng được tham chiếu, thì có! Do đó, với lựa chọn của Cayetano, bạn nhận được tất cả các hàng bạn cần cập nhật / xóa khỏi bảng "con" trước khi bạn thêm ràng buộc mới (FK). Khi tất cả đều trỏ đến các giá trị trong "other_table" thì bạn nên đi!
Armfoot

23

Cắt bớt các bảng và sau đó thử thêm ràng buộc FK .

Tôi biết giải pháp này hơi khó xử nhưng nó hoạt động 100%. Nhưng tôi đồng ý rằng đây không phải là một giải pháp lý tưởng để giải quyết vấn đề, nhưng tôi hy vọng nó có ích.


4
Không cần cắt ngắn mọi thứ. "CẬP NHẬT sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id KHÔNG IN (CHỌN id TỪ sourcecodes)" nên đủ. Hoặc nếu null không được phép trong "sourcecode_id", thì hãy xóa các hàng đó hoặc thêm các giá trị bị thiếu đó vào bảng "sourcecodes".
Torben

1
Đôi khi, nếu dữ liệu tăng PK tự động, nó buộc bạn phải cắt bớt.
François Breton

2
@ShankarDamodaran không chắc tại sao cắt ngắn bảng hoạt động nhưng giải pháp này hoạt động tốt với tôi. Tôi đã có thể khiến các mối quan hệ của mình hoạt động ... CẢM ƠN!
MizAkita

@MizAkita nó hoạt động vì nó xóa các hàng không có giá trị tương ứng trong bảng khác, cho phép tạo ràng buộc mới. Nếu bạn chỉ tìm thấy những hàng đó và cập nhật hoặc xóa chúng (như đề xuất của Cayetano ), bạn không cần phải xóa các hàng khác ...
Armfoot

@Armfoot - Tôi gặp vấn đề này khi thêm hàng đầu tiên vào bảng bằng khóa ngoại. Vì vậy, tôi không có hàng để tìm kiếm.
Krewetka

16

Đối với tôi, vấn đề này hơi khác một chút và siêu dễ kiểm tra và giải quyết.

Bạn phải đảm bảo CẢ HAI bảng của bạn là InnoDB. Nếu một trong các bảng, cụ thể là bảng tham chiếu là MyISAM, ràng buộc sẽ thất bại.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;

14

Điều này cũng xảy ra khi đặt khóa ngoại thành Parent.id thành child.column nếu child.column có giá trị 0 và không có giá trị Parent.id là 0

Bạn sẽ cần đảm bảo rằng mỗi child.column là NULL hoặc có giá trị tồn tại trong Parent.id

Và bây giờ tôi đã đọc bản tuyên bố nos đã viết, đó là những gì anh ta đang xác nhận.


14

Tôi đã có cùng một vấn đề ngày hôm nay. Tôi đã thử nghiệm bốn điều, một số trong số chúng đã được đề cập ở đây:

  1. Có bất kỳ giá trị nào trong cột con của bạn không tồn tại trong cột cha (ngoài NULL, nếu cột con là null)

  2. Các cột con và cha có cùng kiểu dữ liệu không?

  3. Có một chỉ mục trên cột cha mà bạn đang tham khảo? MySQL dường như yêu cầu điều này vì lý do hiệu suất ( http://dev.mysql.com/doc/refman/5.5/en/create-table-forign-keys.html )

  4. Và điều này đã giải quyết nó cho tôi: Cả hai bảng có đối chiếu giống hệt nhau không?

Tôi đã có một bảng trong UTF-8 và bảng khác trong iso-Something. Điều đó đã không làm việc. Sau khi thay đổi bảng iso thành đối chiếu UTF-8, các ràng buộc có thể được thêm vào mà không gặp vấn đề gì. Trong trường hợp của tôi, phpMyAdmin thậm chí không hiển thị bảng con dưới dạng mã hóa iso trong trình đơn thả xuống để tạo ràng buộc khóa ngoại.


7

Dường như có một số giá trị không hợp lệ cho dòng cột 0 không phải là khóa ngoại hợp lệ vì vậy MySQL không thể đặt ràng buộc khóa ngoài cho nó.

Bạn có thể làm theo các bước sau:

  1. Thả cột mà bạn đã cố gắng đặt ràng buộc FK cho.

  2. Thêm nó một lần nữa và đặt giá trị mặc định của nó là NULL.

  3. Cố gắng đặt một ràng buộc khóa ngoại cho nó một lần nữa.


5

Tôi cũng gặp vấn đề tương tự, tôi đã kiểm tra các hàng trong bảng của mình và thấy có sự không tương thích với giá trị của các trường mà tôi muốn xác định khóa ngoại. Tôi đã sửa những giá trị đó, thử lại và vấn đề đã được giải quyết.


4

Tôi cuối cùng xóa tất cả dữ liệu trong bảng của mình và chạy lại thay đổi. Nó hoạt động. Không phải là tuyệt vời, nhưng nó tiết kiệm rất nhiều thời gian, đặc biệt là ứng dụng của bạn vẫn đang trong giai đoạn phát triển mà không có bất kỳ dữ liệu khách hàng nào.


4

thử cái này

SET foreign_key_checks = 0;

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

SET foreign_key_checks = 1;

2

Tôi đã có cùng một vấn đề chính xác về ba lần khác nhau. Trong mỗi trường hợp, đó là do một (hoặc nhiều) hồ sơ của tôi không phù hợp với khóa ngoại mới. Bạn có thể muốn cập nhật các bản ghi hiện tại của mình để tuân theo các ràng buộc cú pháp của khóa ngoại trước khi thử thêm chính khóa đó. Ví dụ sau đây thường cách ly các bản ghi vấn đề:

SELECT * FROM (tablename)
    WHERE (candidate key) <> (proposed foreign key value) 
        AND (candidate key) <> (next proposed foreign key value)

lặp lại AND (candidate key) <> (next proposed foreign key value)trong truy vấn của bạn cho mỗi giá trị trong khóa ngoại.

Nếu bạn có rất nhiều hồ sơ thì điều này có thể khó khăn, nhưng nếu bảng của bạn nhỏ một cách hợp lý thì không nên mất quá nhiều thời gian. Tôi không siêu tuyệt vời trong cú pháp SQL, nhưng điều này luôn cô lập vấn đề đối với tôi.


2

Làm trống cả dữ liệu của bảng và chạy lệnh. Nó sẽ làm việc.


VHanded đã đưa ra câu trả lời tương tự 3 năm trước. Hãy hy vọng không có bất kỳ dữ liệu quan trọng nào trong các bảng ...
xlecoustillier


1

Tôi đã sẵn sàng giải pháp này và ví dụ này có thể giúp đỡ.

Cơ sở dữ liệu của tôi có hai bảng (email và credit_card) với các khóa chính cho ID của chúng. Một bảng khác (máy khách) gọi ID bảng này là khóa ngoại. Tôi có một lý do để có email ngoài dữ liệu khách hàng.

Đầu tiên tôi chèn dữ liệu hàng cho các bảng được tham chiếu (email, credit_card) sau đó bạn nhận được ID cho từng bảng, những ID đó là cần thiết trong bảng thứ ba (máy khách).

Nếu bạn không chèn các hàng đầu tiên vào các bảng được tham chiếu, MySQL sẽ không thể thực hiện các tương ứng khi bạn chèn một hàng mới trong bảng thứ ba tham chiếu các khóa ngoại.

Nếu trước tiên bạn chèn các hàng được tham chiếu cho các bảng được tham chiếu, thì hàng liên quan đến khóa ngoại, không có lỗi xảy ra.

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


mysql chèn vào giá trị email (email) ('xxx@yyy.com'); mysql chèn vào các giá trị ndtc (ndtc, năm, tháng) ('1111222233334444', '2000', '01'); mysql chèn vào các giá trị cliente (nombres, apellidos, telefono, idNDTC, idEmail) ('myname', 'myapp', '5555555555', 1,1);
SubstanceMX

1

Đảm bảo giá trị nằm trong bảng khác nếu không bạn sẽ gặp lỗi này, trong cột tương ứng được chỉ định.

Vì vậy, nếu cột được gán được gán cho một id hàng của bảng khác, hãy đảm bảo có một hàng nằm trong bảng nếu không lỗi này sẽ xuất hiện.


1

bạn có thể thử exapmple này

 START TRANSACTION;
 SET foreign_key_checks = 0;
 ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY 
 (`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 SET foreign_key_checks = 1;
 COMMIT;

Lưu ý: nếu bạn đang sử dụng phpmyadmin, chỉ cần bỏ chọn Bật kiểm tra khóa ngoại

làm ví dụ nhập mô tả hình ảnh ở đây

hy vọng giải pháp này khắc phục vấn đề của bạn :)


1

Bạn chỉ cần trả lời một câu hỏi:

Bảng của bạn đã lưu trữ dữ liệu chưa? (Đặc biệt là bảng bao gồm khóa ngoại.)

Nếu câu trả lời là có, thì điều duy nhất bạn cần làm là xóa tất cả các bản ghi, sau đó bạn có thể tự do thêm bất kỳ khóa ngoại nào vào bảng của mình.

Xóa hướng dẫn: Từ con (bao gồm bảng khóa ngoại) sang bảng cha.

Lý do bạn không thể thêm khóa ngoại sau khi nhập dữ liệu là do sự không nhất quán của bảng, làm thế nào để bạn xử lý một khóa ngoại mới trên bảng cũ chứa đầy dữ liệu?

Nếu câu trả lời là không, thì hãy làm theo hướng dẫn khác.


0
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

sẽ giúp thoát khỏi những ID đó. Hoặc nếu nullkhông được phép vào sourcecode_id, sau đó xóa các hàng đó hoặc thêm các giá trị bị thiếu đó vào sourcecodesbảng.


0

Tôi đã có cùng một vấn đề và tìm thấy giải pháp, đặt NULLthay vì NOT NULLtrên cột khóa ngoại. Đây là một truy vấn:

ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;

MySQL đã thực hiện truy vấn này!


0

Trong trường hợp của tôi, tôi đã tạo một bảng mới có cùng cấu trúc, tạo mối quan hệ với các bảng khác, sau đó trích xuất dữ liệu trong CSV từ bảng cũ có vấn đề, sau đó nhập CSV vào bảng mới và vô hiệu hóa kiểm tra khóa ngoại và vô hiệu hóa gián đoạn nhập, tất cả dữ liệu của tôi được chèn vào bảng mới không có vấn đề thành công, sau đó xóa bảng cũ.

Nó làm việc cho tôi.

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.