首先,我不确定如何搜索这个,所以如果它是重复的,请原谅。我甚至不确定它是否更适合其他StackExchange站点之一;如果是的话,请告诉我,我会在那里问。反正...
我正在做一个爱好项目 - 一个作家的笔记本 - 来练习编程和数据库设计。基本结构非常简单:用户可以创建笔记本,在每个笔记本下,他们可以创建与该笔记本相关的项目。也许笔记本是一系列短篇小说,每个项目都是针对个人故事。
然后,他们可以将项目(场景,角色等)添加到笔记本中的特定项目或笔记本本身,以便它不与特定项目相关联。这样,他们可以拥有跨越多个项目的场景或位置,以及一些特定于特定项目的场景或位置。
我正在尝试在数据库中保留大量逻辑 - 特别是在表结构和约束内,如果可能的话。我对很多项目的基本结构基本上都是这样的(我正在使用MySql,但这是一个非常普遍的问题 - 只是提到它的语法):
CREATE TABLE SCENES(
ID BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
NOTEBOOK BIGINT UNSIGNED NULL,
PROJECT BIGINT UNSIGNED NULL,
....
);
问题是我需要确保设置两个引用中的至少一个,NOTEBOOK和/或PROJECT。它们不必同时设置 - PROJECT引用它所在的NOTEBOOK。我知道我可以只有一个通用的“Parent Id”字段,但我不相信它有可能有一个外来的两张桌子的关键,对吗?还有可能添加额外的交叉引用表 - 即SCENES_X_NOTEBOOKS和SCENES_X_PROJECTS - 但是这很快就会失控,因为我必须为我正在工作的每种不同的项目类型添加类似的表用。这也会引入确保每个项目在交叉引用表中都有条目的问题。
将这种逻辑放在存储过程或应用程序逻辑中很容易,但是如果可能的话,我真的希望将它保留在某种约束中,以消除任何可能性逻辑绕过了一些方法。
有什么想法?我对几乎任何事情都很感兴趣 - 即使它涉及重新设计表格等等。
答案 0 :(得分:3)
关于场景和角色的事情是作家可能会将他们从当前项目中删除。当发生这种情况时,你不想丢失场景和角色,因为作家可能决定在几年后使用它们。
我认为最简单的方法是重新定义:
然后他们可以将项目(场景,角色等)添加到a 笔记本内的具体项目,或笔记本本身 它与特定项目无关。
而不是那样,想想这样说。
然后他们可以将项目(场景,角色等)添加到a 笔记本中的用户定义项目,或系统定义的项目 项目名为“未分配”。项目“未分配”不是为了事情 目前已分配给用户定义的项目。
如果这样做,那么场景和角色将始终分配给项目 - 或者分配给用户定义的项目,或者分配给名为“未分配”的系统定义的项目。
答案 1 :(得分:2)
我不清楚你的要求是什么,但至少让我试着回答你的一些问题......
问题是我需要确保设置两个引用中的至少一个,NOTEBOOK和/或PROJECT。
检查(笔记本不是空或项目不是空)
我不相信有两张表的外键,对吗?
理论上,您可以从同一个字段引用两个表,但这意味着这两个表中的必须包含匹配的行。这可能不是你想要的。
你在这里是正确的轨道 - 让NOTEBOOK成为FK朝向一个桌子的子终点,PROJECT朝向另一个桌面。不会强制使用NULL外键,因此您不必同时设置它们。
还有可能添加额外的交叉引用表 - 即SCENES_X_NOTEBOOKS和SCENES_X_PROJECTS - 但这很快就会失控,因为我必须为每种不同的项目类型添加类似的表格和我一起工作。
如果你在讨论模拟多对多关系的联结(aka .link)表,那么是 - 你必须为参与这种关系的每对表添加它们。
但是,您可以使用继承(也就是类别,子类,子类型,泛化层次结构......)来最小化此类表对的数量。想象一下,你有一组M表必须连接到第二组N表。通常,您已经创建了M * N联结表。但是,如果从公共父表继承第一组中的所有表,并对第二组执行相同操作,则现在可以通过这两个父表之间的一个联结表将它们全部连接起来。
关于继承的完整讨论超出了这里的范围,但您可能希望查看"ERwin Methods Guide",“子类型关系”一章以及this post。
将这种逻辑放在存储过程或应用程序逻辑中很容易,但是如果可能的话,我真的希望将它保留在某种约束中,以消除任何可能性逻辑绕过了一些方法。
你的直觉是正确的 - 让数据库尽可能地从坏数据中“保护”自己。以下是确保数据正确性的偏好顺序:
例如,如果您只需使用声明性数据库约束就可以确保必须遵循某个逻辑,则不要将其放在触发器中。