繁体   English   中英

表 A 或表 B 的外键

[英]Foreign key to table A or table B

考虑这样一种情况,我定义了一个对象、一组对象,然后是一个将它们链接在一起的表:

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 ;

在这里,我提出了一个问题:我也想对 child 应用级联删除,但我不知道 child 是指组还是对象。

我可以向表 obj 或 group 添加外键吗?

我发现的唯一解决方案是添加 child_obj 和 child_grp 字段,添加相关外键,然后在插入对象时使用“特殊”(空类型)组,并在插入子组时执行相反的操作。

考虑关系:

relation_ver1(parent, child_obj, child_group)

我声称这种关系有以下缺点:

  • 您必须处理 NULL 特殊情况。
  • 大约 1/3 的值是 NULL。 NULL 值不好。

幸运的是,有一种简单的方法可以解决这个问题。 由于数据中存在多值依赖关系,您可以将表分解为 2 个符合 4NF 的较小表。 例如:

relation_ver_obj(parent, child_obj)relation_ver_grp(parent, child_group)

我们拥有外键的主要原因不是为了能够执行级联删除等操作。 存在外键的主要原因是参照完整性

这意味着grpid被声明为REFERENCES group(id)以确保grpid永远不会被允许采用任何在 group(id) 中找不到的值。 所以,这是一个有效性问题。 级联DELETE也归结为有效性:如果删除了一个键,那么任何和所有引用该键的外键都将无效,所以很明显,必须对它们做些什么。 级联删除是一种可能的解决方案。 将外键设置为NULL ,从而使关系无效,是另一种可能的解决方案。

你的孩子 id 指的是一个组或一个对象的概念违反了任何参照完整性的概念。 关系数据库理论没有用处,也没有提供多态性。 一个键必须指代一种且仅一种实体。 如果没有,那么您就会开始遇到刚刚发现的问题,但更糟糕的是,您的数据库中没有任何参照完整性保证。 这不是一个很好的情况。

处理与不同类型实体的关系需求的方法是使用一组外键,每个可能的相关实体一个,其中只有一个可能是非空的。 所以,这是它的样子:

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_idchild_group_id是非空的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM