2011-07-30 38 views
16

Tôi đang cố xóa từ nhiều bảng. Đây là những gì bàn của tôi trông giống nhưXóa khỏi nhiều bảng có ràng buộc nước ngoài

A_has_B ---- B ---- C_has_B 
(many to many)  (many to many) 

Tôi cố gắng để xóa tất cả các hàng từ A_has_B, B và C_has_B đưa ID của một kỷ lục trong B. Tôi đang sử dụng MySQL với công cụ lưu trữ InnoDB với các phím nước ngoài quy định cho A_has_B và C_has_B tham khảo ID trong B.

tôi cố gắng để thực hiện tôi xóa như vậy:

DELETE A_has_B.*, C_has_B.*, B.* 

FROM 
A 

join 
B 
on (B.B_id = A.B_id) 

join 
C 
on (C.B_id = B.B_id) 

where B.B_id IN(1,2, 4); 

vấn đề là khi tôi thực hiện truy vấn, mysql than phiền:

Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails (`db`.`C`, CONSTRAINT `fk_C` FOREIGN KEY (`B_id`) REFERENCES `B` (`B_id`) ON DELETE NO ACTION ON UPDATE NO) 

Tôi làm cách nào để khắc phục vấn đề này?

Trả lời

25

Cách đơn giản nhất sẽ được xóa từ mỗi bảng riêng lẻ:

-- Remove all connections from A which reference 
-- the B-rows you want to remove 
DELETE FROM A_has_B 
WHERE B_id IN (1,2,4); 

-- Remove all connections from C which reference 
-- the B-rows you want to remove 
DELETE FROM C_has_B 
WHERE B_id IN (1,2,4); 

-- Finally remove the B-rows 
DELETE FROM B 
WHERE B_id IN (1,2,4); 

MySQL cũng cho phép bạn xóa từ nhiều bảng trong một tuyên bố. Nhưng không có cách nào để kiểm soát thứ tự xóa. Từ manual:

Nếu bạn sử dụng nhiều bảng DELETE tuyên bố liên quan đến các bảng InnoDB mà có ràng buộc khoá ngoại, tôi ưu hoa MySQL có thể xử lý bảng trong một trật tự khác với mối quan hệ cha/con của họ. Trong trường hợp này, câu lệnh không thành công và quay lại. Thay vào đó, bạn nên xóa từ một bảng đơn và dựa vào các khả năng ON DELETE mà InnoDB cung cấp để làm cho các bảng khác được sửa đổi tương ứng.

+0

Cảm ơn câu trả lời của bạn :) Có chắc chắn không thể xóa bằng một câu lệnh không? Tôi có thể nghĩ rằng có lẽ tôi có thể buộc MySQL xóa khỏi bảng intersectoin trước khi xóa khỏi B. – F21

+2

Trong SQL, bản chất của 'transactional' được thiết kế để cho phép nhiều câu lệnh hoàn thành * as-if * chúng là một câu lệnh đơn . Thay vì triển khai cả một ngôn ngữ phức tạp không thể hiểu được và một động cơ/trình tối ưu hóa không thể phức tạp.Vì vậy, nếu điều quan trọng là mọi thứ đều bị xóa "cùng một lúc", hãy xem xét các giao dịch :) – MatBailie

0

Thực hiện xóa trong các số liệu riêng biệt và nó sẽ hoạt động.

8

Trên thực tế, trong MySQL, bạn có thể tắt kiểm tra các ràng buộc khoá ngoại

SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; 
--your SQL statements 
SET [email protected]_FOREIGN_KEY_CHECKS; 

Những tuyên bố trên dòng đầu tiên buộc máy chủ MySQL để tắt kiểm tra chính nước ngoài và dòng cuối cùng biến chúng lại trên (rất quan trọng). Hai điều cần lưu ý:

  • Đó là khá nguy hiểm để tắt kiểm tra các hạn chế và không phải là cái gì đó nên được thực hiện trong, chẳng hạn, một DB sản xuất ... cách an toàn nhất là sử dụng báo cáo riêng biệt .
  • Luôn luôn bật chế kiểm tra lại trên
3

Bạn có thể chỉ định "xoá thác" trên chính nước ngoài. Khi bạn xóa hàng gốc, công cụ mysql sẽ xóa các bản ghi trong các bảng con liên quan

Các vấn đề liên quan