Mysql 如何在单表继承上强制引用完整性?

Mysql 如何在单表继承上强制引用完整性?,mysql,polymorphic-associations,single-table-inheritance,cascading-deletes,referential-integrity,Mysql,Polymorphic Associations,Single Table Inheritance,Cascading Deletes,Referential Integrity,我已经阅读了一些答案,并认为这种方法对我正在考虑的设置是有益的: Playlist -------- id AUTO_INCREMENT title TeamPlaylist ------------ id REFERENCES Playlist.id teamId REFERENCES Team.id UserPlaylist ------------ id REFERENCES Playlist.id userId REFERENCES User.id PlaylistVideo --

我已经阅读了一些答案,并认为这种方法对我正在考虑的设置是有益的:

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
选项都设置为
DELETE
,当
播放列表
被删除时,该选项将正常工作。但是,如果
用户
团队
被删除,会发生什么情况

即,如果删除了
用户
,则
用户播放列表
中的行将被删除,但
播放列表
播放视频
中的引用行将保留。我曾考虑在删除后将其作为
触发器执行,但无法知道删除请求是因为
播放列表
被删除还是
用户
被删除

在这种情况下,加强诚信的最佳方式是什么

编辑(提供ERD)


好的,我知道你想要什么了。。。您要做的是像这样运行查询

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

从用户或团队中删除行后

您可以在
用户
团队
表上实现触发器,每当从以下任一位置删除行时执行:

用户表:

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 ;
团队表:

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
操作将使用将要删除的
id
播放列表
表上自动执行(通过内部联接)


我已经测试过了,效果很好。

赞恩·宾的答案很明显,非常好。但是我有一个想法,不用触发器就可以完成,因为触发器有很多问题

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

使用单个
事务
并使数据库
自动提交为false

为播放列表和播放视频中的引用行编写删除查询。您必须首先使用该引用id(带有where条件)手动编写此查询并运行它

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

最后,使事务
自动提交为真


它正在成功地工作,希望它会有所帮助

在我看来,问题在于您的
用户
团队
表应该具有超类型表(例如
聚会
),而不是播放列表表

正如您所指出的,在播放列表上执行“表继承”会在试图确定要删除哪些内容时受到惩罚。当您将继承向上移动到用户/团队级别时,所有这些问题都会消失

你可以看到

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

基本概念是超类型表允许您实现数据库类型的多态性。当您正在处理的表需要链接到一组子类型中的任何一个时,您只需将FK指向超类型即可,这将自动获得所需的“一次仅链接其中一个”业务约束。超级类型与每个子类型表都有“一对零或一”关系,并且每个子类型表在其主键中使用与超级类型表中的主键相同的值


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

我不明白UserPlaylist怎么可能是播放列表的继承。这不是一个关系表吗?我不明白你的问题。UserPlaylist与Playlist相关,只是id来自Playlist.id。这里还有一些关于单表继承的问题-您不希望被删除的用户删除播放列表和播放列表视频行的全部原因是,它们也可能被其他userplaylist或teamplaylist记录引用。谢谢您的评论,但我觉得我不理解我想要的内容完成。播放列表将仅引用UserPlaylist或TeamPlaylist中的一个。因此,为什么Playlist.id是自动递增的,而UserPlaylist.id和TeamPlaylist.id不是。如果您需要进一步的澄清,请让我知道,我会编辑我的问题@Sebas-你能提供一个你认为应该是什么样子的模型设置示例吗?这将有助于我理解你的意思。你可以用一个更简单、更准确的ERD来表达你的问题。也许使用MySQL Workbench.brilliant解决方案。我自己没有测试过,但看起来很可靠+好主意,赞恩。出于某种原因,我没有考虑在用户或团队表上设置触发器-仅在UserPlaylist或TeamPlaylist表上设置触发器。这是一个好观点,也是一个好主意。然而,在这个系统中,团队与用户有很大的不同。用户可以登录,团队不能。这是生产中的现有系统(播放列表是新的)。如果我是从零开始建造的话,这可能就是我要走的路。但我需要仔细考虑是否值得更改此设置(即团队和用户当前将有重叠的ID)。但是谢谢你的建议。这就是子类型表的作用:它们的不同之处。更改的真正问题是更新其中一个集合的ID,并删除和重新创建约束。但我认为这是值得的谢谢你选择我的答案!是什么让你决定这样做的?在这个数据库中,我还有FollowUser、FollowTeam和followPort表。我将能够用一个单表替换这些设置。如果我不改变,这种情况将来可能会再次出现。此外,我们正在对网站进行重大修改