考虑一种情况,我定义一个对象,一组对象,然后是一个将它们链接在一起的表:
CREATE TABLE obj (
id INTEGER PRIMARY KEY,
name text
) ;
CREATE TABLE group (
id INTEGER PRIMARY KEY ;
grpname TEXT
) ;
CREATE TABLE relation (
objid INTEGER,
grpid INTEGER,
PRIMARY KEY (objid, grpid)
) ;
我正在寻找适用的级联删除,所以我添加了外键
ALTER TABLE relation
ADD FOREIGN KEY (objid)
REFERENCES obj(id)
ON DELETE CASCADE ;
ALTER TABLE relation
ADD FOREIGN KEY (grpid)
REFERENCES group(id)
ON DELETE CASCADE ;
到目前为止一切都好。现在假设我想添加对组的支持。我想改变这样的关系表:
CREATE TABLE relation_ver1 (
parent INTEGER,
child INTEGER,
PRIMARY KEY (parent, child)
) ;
ALTER TABLE relation_ver1
ADD FOREIGN KEY (parent)
REFERENCES group(id)
ON DELETE CASCADE ;
在这里我得到了一个问题:我也想对孩子应用级联删除,但我不知道这里是否有孩子指的是一个团体或对象。
我可以在表obj或组中添加外键吗?
我找到的唯一解决方案是添加child_obj和child_grp字段,添加相对外键然后,当插入例如对象时使用'特殊'(排序为null)组,并在插入子组时执行相反操作
答案 0 :(得分:1)
我们拥有外键的主要原因是不,以便能够执行级联删除等操作。外键存在的主要原因是 引用完整性 。
这意味着grpid
被声明为REFERENCES group(id)
,以确保永远不会允许grpid
获取在组(id)中找不到的任何值。所以,这是一个有效性的问题。级联DELETE
也归结为有效性:如果删除了一个密钥,那么引用该密钥的任何和所有外键都将无效,因此显然必须对它们进行某些操作。级联删除是一种可能的解决方案。将外键设置为NULL
,从而使关系无效,这是另一种可能的解决方案。
您拥有儿童身份证的概念指的是群体或对象违反任何参照完整性概念。关系数据库理论没有用,也没有提供多态性。密钥必须引用一种且仅一种实体。如果没有,那么您开始遇到类似您刚发现的问题,但更糟糕的是,您不能在数据库中拥有任何参照完整性保证。这不是一个好的情况。
处理与不同类型实体的关系需求的方法是使用一组外键,每个可能的相关实体一个,其中只有一个可能是非NULL。所以,这是它的样子:
CREATE TABLE tree_relation (
parent_id INTEGER,
child_object_id INTEGER,
child_group_id INTEGER,
PRIMARY KEY (parent_id, child_object_id, child_group_id) );
ALTER TABLE tree_relation
ADD FOREIGN KEY (parent_id) REFERENCES group(id) ON DELETE CASCADE;
ALTER TABLE tree_relation
ADD FOREIGN KEY (child_object_id) REFERENCES object(id) ON DELETE CASCADE;
ALTER TABLE tree_relation
ADD FOREIGN KEY (child_group_id) REFERENCES group(id) ON DELETE CASCADE;
您需要做的就是确保child_object_id
,child_group_id
中只有一个非NULL。
答案 1 :(得分:1)
考虑关系:
relation_ver1(parent, child_obj, child_group)
我声称这种关系有以下缺点:
幸运的是,有一种简单的方法可以解决这个问题。由于数据中存在多值依赖关系,因此可以将表分解为2个符合4NF的较小表。例如:
relation_ver_obj(parent, child_obj)
和
relation_ver_grp(parent, child_group)
。