【问题标题】:Deleting foreign key references in a database table删除数据库表中的外键引用
【发布时间】:2012-12-23 11:03:00
【问题描述】:

鉴于这个问题:

考虑一个关系geq,它表示“大于或等于”, 也就是说,(x,y)E geq 仅当 y

create table geq
( lb integer not null 
, ub integer not null
, primary key lb
, foreign key (ub) references geq on delete cascade )

如果删除元组 (x,y),以下哪项可能?

(a) 删除 z > y 的元组 (z,w)
(b) 删除 z > x 的元组 (z,w)

这就是我试图解决它的方法:-

由于 ub(上限)是外键,所以在元组 (x,y) 中,y 是外键。 鉴于表 geq 本身的外键 (y) 引用,geq 中必须有一个元组 (y , y' )。

现在,y >= x 并且 y' >= y。因此,y' >= x。

所以我没有使用 (z,w),而是使用了 (y,y')。

那么,答案不应该是,一个带有 w>x 的元组 (z,w) 被删除了吗?

(我正在尝试解决旧的 GATE 论文)

【问题讨论】:

  • y

标签: database-design foreign-keys relational-database foreign-key-relationship database-table


【解决方案1】:

如果 (x,y) ∈ geq 当且仅当 x > y。将关系称为“大于或等于”是用词不当,原因我将在下面介绍。

外键是上限(ub)是正确的,这意味着 x 是外键,y 是元组中的主键(x ,y)。外键声明中的on delete cascade 选项意味着每当删除一条记录时,所有引用已删除记录的子记录也将被删除。

对于您的情况,如果您删除元组 (x,y),任何引用 (x,y) 的记录也将被删除。

由于外键是ub,记录 (z,w) 是 (x,y) 的子当且仅当:z = y。

因此,对于 (x,y) 的删除会导致 (z,w) 的级联删除,必须满足以下条件:

x ≥ y = z ≥ w (这不太对,稍后我会解释。)

因此,您的问题的答案是 (a) 和 (b) 都不正确。此外,您的结论(不在列出的选项中)也不正确,w 必须≤ x,而不是 w > x

事实上,由于下限是主键,关系 (a,a) 不可能有子记录,因为这需要违反主键。因此,上限必须严格大于记录的下限才能有任何子记录。这意味着上面的关系陈述更恰当:

x ≥ y = z > w 因为 y ≠ w

这意味着当一个元组 (x,y) 被删除时,你只能说一个元组 (z,w) 可能被级联删除,这样 z = y 或 zx.

【讨论】:

  • 当然(a, a) 有一个子记录是必要的,假设我们在lb <> ub? 的位置插入记录?由于这是一个自引用不可为空的键,因此第一个插入必须是 (a, a) 引用自身。后续插入的格式必须为 (b, a)(b, b)
  • @ChrisSaxon - 也许我应该更清楚。 (a,a) 不可能有一个单独的 子记录 (a,a),因为这会违反 PK。由于问题是关于级联删除,而级联删除不会删除父记录两次,我不认为 (a,a) 是自引用的这一事实对这个问题很重要。
【解决方案2】:

问题是 NOT NULLable 外键,结合 'y

有两种方法可以为没有父节点的节点创建哨兵值:

  • 将链接指针设置为 NULL
  • 将其设置为与 id 相同的值。

代码示例:

CREATE TABLE geq_one
    ( id INTEGER NOT NULL PRIMARY KEY
    , parent_id INTEGER  NOT NULL REFERENCES geq_one(id) ON DELETE CASCADE
    , CONSTRAINT younger_than_parent_one CHECK (parent_id <= id)
    )
        ;
INSERT INTO geq_one(id,parent_id) VALUES
(1,1) -- sentinel
, (2,1)
, (3,1)
        ;

CREATE TABLE geq_two
    ( id INTEGER NOT NULL PRIMARY KEY
    , parent_id INTEGER  REFERENCES geq_two(id) ON DELETE CASCADE
    , CONSTRAINT younger_than_parent_two CHECK (parent_id < id)
    )
        ;
INSERT INTO geq_two(id,parent_id) VALUES
(1,NULL) -- sentinel
, (2,1)
, (3,1)
        ;

DELETE FROM geq_one WHERE id = 1;
SELECT * FROM geq_one;

DELETE FROM geq_two WHERE id = 1;
SELECT * FROM geq_two;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 2021-12-24
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多