13

Tôi đã đọc một số câu trả lời về Bill Karwin'ssingle table inheritance và nghĩ rằng phương pháp này sẽ tốt cho việc thiết lập Tôi đang xem xét:Làm cách nào để thực thi tính toàn vẹn tham chiếu trên Thừa kế Bảng đơn?

Playlist 
-------- 
id AUTO_INCREMENT 
title 

TeamPlaylist 
------------ 
id REFERENCES Playlist.id 
teamId REFERENCES Team.id 

UserPlaylist 
------------ 
id REFERENCES Playlist.id 
userId REFERENCES User.id 

PlaylistVideo 
------------- 
id 
playlistId REFERENCES Playlist.id 
videoId REFERENCES Video.id 

Tất cả các tùy chọn CASCADE được thiết lập để DELETE mà sẽ làm việc một cách chính xác khi một Playlist là đã xóa, tuy nhiên, điều gì sẽ xảy ra nếu một số User hoặc Team bị xóa?

tức là. Nếu một số User bị xóa, các hàng trong UserPlaylist sẽ bị xóa nhưng các hàng được tham chiếu trong PlaylistPlaylistVideo sẽ vẫn còn. Tôi nghĩ về việc thực thi điều này dưới dạng TRIGGER AFTER DELETE nhưng không có cách nào để biết liệu yêu cầu xóa có đến vì Playlist đã bị xóa hay nếu User bị xóa.

Cách tốt nhất để thực thi tính toàn vẹn trong tình huống này là gì?

Chỉnh sửa (Cung cấp ERD)

enter image description here

+1

Tôi không hiểu cách UserPlaylist có thể là một thừa kế của Danh sách phát. Nó không phải là một bảng quan hệ thay thế? – Sebas

+0

Tôi không hiểu câu hỏi của bạn. UserPlaylist có liên quan đến Playlist chỉ là id đến từ Playlist.id. Dưới đây là một số câu hỏi khác về Thừa kế bảng đơn - http://stackoverflow.com/a/3383320/47278 –

+0

toàn bộ lý do bạn không muốn người dùng bị xóa xóa hàng danh sách phát và danh sách phát là vì họ cũng có thể tham chiếu bởi các bản ghi danh sách người chơi hoặc danh sách người chơi khác. – WebChemist

Trả lời

3

Theo quan điểm của tôi, vấn đề là các bảng UserTeam của bạn là bảng cần có bảng siêu kiểu (chẳng hạn như Party), không phải bảng danh sách phát.

Như bạn đã chỉ ra, việc "kế thừa bảng" của bạn trên danh sách phát đi kèm với các hình phạt khi cố gắng tìm ra nội dung cần xóa. Tất cả những vấn đề đó biến mất khi bạn di chuyển thừa kế lên đến cấp độ người dùng/nhóm.

Bạn có thể xem this answer for more detail about supertyping/subtyping.

Tôi rất tiếc khi không cung cấp mã vì tôi không biết cú pháp MySQL của tim.

Khái niệm cơ bản là bảng siêu kiểu cho phép bạn triển khai loại đa hình cơ sở dữ liệu. Khi bảng bạn đang làm việc với nhu cầu liên kết với bất kỳ một nhóm nào là của một nhóm các loại phụ, bạn chỉ cần thực hiện điểm FK cho siêu kiểu thay thế và điều này sẽ tự động đưa bạn "chỉ một lần một" ràng buộc kinh doanh. Loại siêu có mối quan hệ "một-không-hoặc-một" với mỗi bảng loại phụ và mỗi bảng loại phụ sử dụng cùng giá trị trong PK của nó dưới dạng PK từ bảng siêu kiểu.

Trong cơ sở dữ liệu của bạn, bằng cách chỉ có một bảng Playlist có FK đến Party (PartyID), bạn có thể dễ dàng thực thi quy tắc kinh doanh của mình ở cấp cơ sở dữ liệu mà không cần trình kích hoạt.

+0

Đây là một điểm tốt và ý tưởng hay. Tuy nhiên, trong hệ thống này, một Nhóm khác với Người dùng. ví dụ. Người dùng có thể đăng nhập, một Nhóm không thể. Đây là một hệ thống hiện có trong sản xuất (trong khi Playlists là mới). Nếu tôi đã xây dựng nó từ đầu, điều này có lẽ sẽ là con đường để đi. Nhưng tôi cần phải suy nghĩ kỹ nếu cần thay đổi thiết lập này (ví dụ: Nhóm và Người dùng hiện có ID trùng lặp). Nhưng cảm ơn đề nghị. –

+0

Đó là những gì mà các bảng loại phụ dành cho: cách thức chúng khác nhau. Vấn đề thực sự trong việc thay đổi là cập nhật các ID cho một trong các bộ, với các ràng buộc giảm và tái tạo. Nhưng tôi nghĩ nó đáng giá. :) – ErikE

+0

Cảm ơn bạn đã chọn câu trả lời! Điều gì khiến bạn quyết định đây là con đường để đi? – ErikE

4

OK tôi thấy những gì bạn muốn ở đây ... những gì bạn muốn làm là chạy một truy vấn như

DELETE FROM playlist 
WHERE  id 
NOT IN  (
    SELECT id 
    FROM UserPlayList 
    UNION 
    SELECT id 
    FROM TeamPlayList 
) 

sau khi một trong hai liên tiếp là bị xóa khỏi một trong hai người dùng hoặc nhóm

11

Những việc bạn có thể làm là triển khai trình kích hoạt trên các bảng UsersTeam của bạn ute bất cứ khi nào hàng được xóa từ một trong hai:

bảng User:

DELIMITER $$ 
CREATE TRIGGER user_playlist_delete 
BEFORE DELETE ON User FOR EACH ROW 
BEGIN 
    DELETE a FROM Playlist a 
    INNER JOIN UserPlaylist b ON a.id = b.id AND b.userId = OLD.id; 
END$$ 
DELIMITER ; 

Đội bảng:

DELIMITER $$ 
CREATE TRIGGER team_playlist_delete 
BEFORE DELETE ON Team FOR EACH ROW 
BEGIN 
    DELETE a FROM Playlist a 
    INNER JOIN TeamPlaylist b ON a.id = b.id AND b.teamId = OLD.id; 
END$$ 
DELIMITER ; 

gì những trigger sẽ làm là mỗi lần một kỷ lục bị xóa khỏi một của các bảng này, hoạt động DELETE sẽ tự động thực hiện trên bảng Playlists bằng cách sử dụng id sắp bị xóa (thông qua một tham gia bên trong).

Tôi đã thử nghiệm tính năng này và nó hoạt động tốt.

+0

giải pháp tuyệt vời. đã không thử nghiệm nó myslef, nhưng trông rắn.+1 – techtheatre

+0

Ý tưởng hay Zane. Vì lý do nào đó, tôi đã không nghĩ đến việc đặt trình kích hoạt trên bảng Người dùng hoặc Nhóm - chỉ có các bảng UserPlaylist hoặc TeamPlaylist. –

+0

Tôi không nghĩ đây là cách tốt nhất để giải quyết vấn đề ... – ErikE

1

Câu trả lời của Zane Bien khá rõ ràng & superb.But Tôi có một ý tưởng để làm điều này mà không cần sử dụng trigger vì trigger có nhiều vấn đề.

Bạn có đang sử dụng bất kỳ ngôn ngữ lập trình nào không? Nếu có thì,

Sử dụng một đơn transaction và làm cho cơ sở dữ liệu của bạn auto commit false

viết một truy vấn xóa cho các hàng được tham chiếu trong danh sách nhạc và PlaylistVideo. Theo cách thủ công, bạn phải viết truy vấn này trước bằng cách sử dụng id tham chiếu đó (với điều kiện ở đâu) và chạy nó.

Bây giờ hãy chuẩn bị một truy vấn khác cho nhiệm vụ chính của bạn, nghĩa là xóa Người dùng và các hàng trong UserPlaylist sẽ bị xóa tự động (do tùy chọn CASCADE DELETE).Bây giờ hãy chạy truy vấn thứ hai của bạn và commit.

Cuối cùng, hãy thực hiện giao dịch của bạn auto commit true.

Nó đang hoạt động thành công, hy vọng nó sẽ hữu ích.

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