44

Tôi có bảng sau 'bình luận' trong ứng dụng của tôi:MySQL - Conditional ràng buộc khoá ngoại

comments 
-------- 
id   INT 
foreign_id INT 
model  TEXT 
comment_text TEXT 
... 

ý tưởng của bảng này là để lưu trữ ý kiến ​​cho các bộ phận khác nhau của ứng dụng của tôi - nó có thể lưu trữ bình luận cho bài viết trên blog ví dụ: hình ảnh

1|34|blogpost|lorem ipsum... 

sử dụng:

2|12|picture|lorem ipsum... 

và vân vân.

bây giờ, có cách nào để buộc ràng buộc KEY NGOẠI HỐI trên dữ liệu đó không?

ví dụ: một cái gì đó như thế này trong bảng nhận xét:

FOREIGN KEY (`foreign_id`) REFERENCES blogposts (`id`) 
//but only when model='blogpost' 

Trả lời

71

Bạn đang cố gắng để làm một thiết kế đó được gọi là Hiệp hội đa hình. Đó là, khóa ngoại có thể tham chiếu các hàng trong bất kỳ bảng nào có liên quan.

Nhưng ràng buộc khóa ngoài phải tham chiếu chính xác một bảng. Bạn không thể khai báo khóa ngoài tham chiếu các bảng khác nhau tùy thuộc vào giá trị trong một cột khác trong bảng Comments của bạn. Điều này sẽ vi phạm một số quy tắc thiết kế cơ sở dữ liệu quan hệ.

Giải pháp tốt hơn là tạo một loại "siêu cấp" được tham chiếu bằng nhận xét.

CREATE TABLE Commentable (
    id SERIAL PRIMARY KEY 
); 

CREATE TABLE Comments (
    comment_id SERIAL PRIMARY KEY, 
    foreign_id INT NOT NULL, 
    ... 
    FOREIGN KEY (foreign_id) REFERENCES Commentable(id) 
); 

Mỗi loại nội dung của bạn sẽ được coi là loại phụ của điều này. Điều này tương tự với khái niệm hướng đối tượng của giao diện .

CREATE TABLE BlogPosts (
    blogpost_id INT PRIMARY KEY, -- notice this is not auto-generated 
    ... 
    FOREIGN KEY (blogpost_id) REFERENCES Commentable(id) 
); 

CREATE TABLE UserPictures (
    userpicture_id INT PRIMARY KEY, -- notice this is not auto-generated 
    ... 
    FOREIGN KEY (userpicture_id) REFERENCES Commentable(id) 
); 

Trước khi bạn có thể chèn một hàng vào BlogPosts hoặc UserPictures, bạn phải chèn một hàng mới để Commentable để tạo ra một id pseudokey mới. Sau đó, bạn có thể sử dụng id được tạo khi bạn chèn nội dung vào bảng loại phụ tương ứng.

Khi bạn làm tất cả những điều đó, bạn có thể dựa vào các ràng buộc toàn vẹn tham chiếu.

+1

Tôi giả định UserPictures chứa trường user_id tham chiếu đến bảng Người dùng. Làm thế nào để bạn xử lý một người dùng xóa theo cách mà xóa sẽ cascade đến bảng Commentable? Tôi đã hỏi câu hỏi này ở đây - http://stackoverflow.com/questions/11497149/how-to-enforce-referential-integrity-on-single-table-inheritance - và sẽ biết ơn nếu bạn có thể giải thích cách bạn xử lý nấc tôi đang bị mắc kẹt. –

+13

@MattMcCormick, tôi không trả lời các câu hỏi trên SO nữa, bởi vì những người kiểm duyệt đáng ghét đã làm cho nó không được phép tham gia. –

+2

Oh ok. Cảm ơn sự tham gia của bạn trong quá khứ. Tôi đọc khá một vài câu trả lời của bạn liên quan đến thừa kế bảng đơn và các hiệp hội đa hình và cũng đã xem các trang trình bày từ cuộc trò chuyện của bạn mà bạn đã tham chiếu trong một trong số chúng. Nó giúp tôi xác định tốt hơn các tình huống với cơ sở dữ liệu có thể dẫn đến vấn đề xuống đường. Tôi đã thêm cuốn sách của bạn vào danh sách đọc của tôi và có lẽ sẽ chọn nó cho cuốn sách phần mềm tiếp theo của tôi để đọc. –

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