禁止级联删除的外键约束
Posted
技术标签:
【中文标题】禁止级联删除的外键约束【英文标题】:foreign key constraints forbiding cascading delete 【发布时间】:2015-08-18 20:34:49 【问题描述】:我的团队可以分配团队成员和人员。团队表和人员表已存在且无法触及,我正在创建联接表以分配团队成员和团队领导。
我有一个关键约束,团队负责人必须是团队成员,只要有人被指定为团队负责人,就不可能将他们作为团队成员移除。
我的 sql 看起来像这样(从更复杂的表翻译,如果我的示例输入错误,请原谅我,因为我是手动编写的)
CREATE TABLE TEAM_MEMBERS (id BIGINT NOT NULL,
teamId BIGINT NOT NULL,
personId BIGINT NOT NULL,
PRIMARY KEY (id),
KEY (teamId),
KEY (personId)
CONSTRAINT fk_team FOREIGN KEY (teamId) REFERENCES TEAM(id) ON DELETE CASCADE);
CREATE TABLE TEAM_LEAD (id BIGINT NOT NULL,
teamId BIGINT NOT NULL,
personId BIGINT NOT NULL,
PRIMARY KEY (id),
KEY (teamId),
KEY (personId),
CONSTRAINT fk_team_u FOREIGN KEY (teamId) REFERENCES TEAM (id) ON DELETE CASCADE,
CONSTRAINT fk_child FOREIGN KEY (teamId, personId) REFERENCES TEAM_MEMBERS(teamId, personId)) ON DELETE RESTRICT;
这不起作用。当一个团队被删除时,我会遇到约束违规,因为它首先将删除级联到 team_members,然后尝试删除它,然后发现 team_lead 正在阻止它。
我的问题,有没有一种简单的方法在这里表达某种操作顺序,让 sql 明白它应该首先删除团队领导,或者理解如果它完全级联删除它不是约束违规?
我意识到一种解决方案是让 teamLead 成为 team_members 上的布尔值,而不是单独的连接表。由于各种原因,我不想这样做,但如果没有其他更清洁的解决方案,也可以这样做。
我们在服务器上使用 PostgreSQL,H2 用于我们的测试,但如果可能的话,我们不希望被绑定到数据库。
【问题讨论】:
"如果可能的话,我们不希望被绑定到数据库" - 您是否以不绑定到 Web 的方式创建 Web 应用程序 -框架?或者您的 GUI/桌面应用程序,以便您不依赖于 GUI 框架?还是您的应用程序本身不依赖于特定的编程语言? 为什么不在 team_members 上有一个名为 IsTeamLead 的布尔列?我不明白你为什么需要一个单独的 team_lead 表。 您是否有理由不简单地将fk_child
约束移动到 TEAM_MEMBERS
并反转它? CONSTRAINT fk_parent FOREIGN KEY (teamId, personId) REFERENCES TEAM_LEAD(teamId, personId)) ON DELETE SET DEFAULT;
还是我只是遗漏了一些明显的东西?
【参考方案1】:
这个 SQL 约束不应该在这里:
CONSTRAINT fk_child FOREIGN KEY (teamId, personId) REFERENCES TEAM_MEMBERS(teamId, personId)) ON DELETE RESTRICT;
您的数据模型似乎错误:团队负责人不应有指向团队成员的外键,而应仅指向团队。
能否请您发布完整的架构,以便我们提供更完整的答案?
【讨论】:
完整的架构相当...复杂。我简化了它,因为它很难理解并且里面有一些平息的东西。然而,除此之外,我们的“团队”更像是可以指派人们解决/处理的现有情况(因此独立于任何人或领导被指派)我认为描述描述了与这个问题相关的所有内容。我们的团队和人员存在,我需要分配多人来解决“团队”问题并让其中一人担任领导者。由于我们的抽象层在 team_members 上有一个布尔值来代表领导者是 awkwar 但那行显然是错误的。我同意布尔值是个坏主意。您需要有一个额外的表来处理团队成员和团队之间的连接,而不是团队成员和团队负责人之间的连接。 另外一件奇怪的事情:当团队解散时,您不应该将删除传播给团队成员。他们应该留在分贝,但他们以前在团队中的角色已经消失了。他们可能仍然在另一个团队中担任角色。 people 是它自己的表,与团队成员分开(这只是一个连接表),因此我们可以将删除级联到团队成员,而无需自己删除人员。 " 由于我们的抽象层在 team_members 上有一个布尔值来表示领导者是 awkwar" - 设计应该从数据模型开始,而不是抽象层,否则,您最终会得到以下类型你看到的问题。正如已经指出的那样,没有充分的理由将 team_lead 作为单独的表,因为您可以将该信息存储在 team_members 表中。我的建议是让数据模型正确,因为如果你在那里失败了,其他的都不重要。对数据模型进行 hack 以“使其工作”与您的抽象层会产生不好的结果。以上是关于禁止级联删除的外键约束的主要内容,如果未能解决你的问题,请参考以下文章