14

我已经阅读了Bill Karwin关于单表继承的一些答案,并认为这种方法对我正在考虑的设置很有用:

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

所有CASCADE选项都设置为在删除DELETEa 时可以正常工作Playlist,但是,如果 a UserorTeam被删除会发生什么?

IE。如果 aUser被删除,则 in 中的行将被删除,但 in和UserPlaylist中的引用行将保留。我考虑过强制执行此操作,但无法知道删除请求是因为被删除还是被删除而产生的。PlaylistPlaylistVideoTRIGGER AFTER DELETEPlaylistUser

在这种情况下执行完整性的最佳方法是什么?

编辑(提供 ERD)

在此处输入图像描述

4

4 回答 4

11

您可以做的是在您的表UsersTeam表上实现触发器,只要从以下任一表中删除行,该触发器就会执行:

用户表:

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 ;

团队表:

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 ;

这些触发器的作用是每次从这些表之一中删除记录时,将使用即将删除DELETE的表自动执行操作(通过内部连接)。Playlistsid

我已经对此进行了测试,并且效果很好。

于 2012-07-19T01:51:29.503 回答
4

好的,我在这里看到你想要的......你想要做的是运行一个查询

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

从用户或团队中删除任何一行之后

于 2012-07-18T05:17:18.420 回答
3

在我看来,问题在于你的UserTeam表应该有一个超类型表(例如Party),而不是播放列表表。

正如您所指出的,在尝试找出要删除的内容时,对播放列表进行“表继承”会受到惩罚。当您将继承提升到用户/团队级别时,所有这些问题都会消失。

您可以查看此答案以获取有关超类型/子类型的更多详细信息

很抱歉没有提供代码,因为我不知道 MySQL 的语法。

基本概念是超类型表允许您实现一种数据库类型的多态性。当您正在使用的表需要链接到一组子类型中的任何一个时,您只需将 FK 指向超类型,这会自动为您提供所需的“一次只有一个”业务约束. 超类型与每个子类型表具有“一对零或一”的关系,并且每个子类型表在其 PK 中使用与超类型表中的 PK 相同的值。

在您的数据库中,通过只有一个Playlist带有 FK to 的表Party (PartyID),您可以轻松地在数据库级别执行您的业务规则,而无需触发器。

于 2012-07-24T23:47:55.773 回答
1

Zane Bien 的答案非常明显和精湛。但我有一个不使用触发器的想法,因为触发器有很多问题。

你在使用任何编程语言吗?如果是的话,

使用单个transaction并使您的数据库auto commit false

为 Playlist 和 PlaylistVideo 中的引用行编写删除查询。您必须先手动使用该引用 ID(带有 where 条件)编写此查询并运行它。

现在为您的主要任务准备另一个查询,即删除用户,并且 UserPlaylist 中的行将被自动删除(由于CASCADE DELETE选项)。现在运行您的第二个查询和commit

最后进行交易auto commit true

它工作成功,希望它会有所帮助。

于 2012-07-23T09:51:09.367 回答