如何在关系数据库中建模排它关系?

问题描述 投票:0回答:1

有 3 张桌子:

A
B
C
A
中的行可以与
B
中的行关联,也可以与
C
中的行关联,但不能同时与
B
C
关联。 换句话说,关联是异或、一对一的。

以下是一些建议的替代方案:

  1. B
    持有
    A
    (
    B.A_id
    ) 的外键,
    C
    持有
    A
    (
    C.A_id
    ) 的外键。我想不出有什么办法可以限制协会的排他性。
  2. A
    拥有一个指向
    B
    (
    A.B_id
    ) 的外键,以及另一个指向
    C
    (
    A.C_id
    ) 的外键。我们可以通过
    CHECK (A_id IS NULL AND B_id IS NOT NULL) OR (A_id IS NOT NULL AND B_id IS NULL)
    来限制排他性。但我们按宽度(内存和磁盘)付费,因为我们不使用一半的外键列。
  3. A
    保存一个不受约束的列 (
    A.foreign_id
    ),它可以是
    B
    C
    的键,并且
    A
    保存表示类型的另一列(
    A.foreign_type
    =
    B
    C
    )。这满足了排他性约束,并最小化了宽度,但失去了外键约束验证,并使查询变得复杂(我加入的人是基于
    A.foreign_type
    列)

哪个规模最好?是否有未列出的优点/缺点可供讨论?还有其他替代方案可以考虑吗?

database database-design foreign-keys relational-database database-schema
1个回答
0
投票

替代方案 1. 这种方法的问题在于

A
可能包含与
B
C
中不同的内容。如果您可以接受这种情况,那么以下设计(概念上)可能是您的排他性问题的解决方案:

CREATE TABLE A
(
    type SMALLINT,
    id   INTEGER,
    PRIMARY KEY (type, id)
);

CREATE TABLE B
(
    type SMALLINT,
    id   INTEGER,
    PRIMARY KEY (type, id),
    CHECK ( type = 1 ),
    FOREIGN KEY (type, id) REFERENCES A (type, id)
);

CREATE TABLE C
(
    type SMALLINT,
    id   INTEGER,
    PRIMARY KEY (type, id),
    CHECK ( type = 2 ),
    FOREIGN KEY (type, id) REFERENCES A (type, id)
);

替代方案 2. 这种方法的问题在于

B
C
可能包含
A
不会包含的内容。如果这对您来说不是问题,那么我根本不用担心磁盘空间(检查这一点的最佳方法是进行实验)。

替代方案 3. 如果您想要有限制,请考虑制作一张表

BC
而不是两张表
B
C

CREATE TABLE BC
(
    type    SMALLINT,
    id      INTEGER,
    b_field INT,
    c_field INT,
    PRIMARY KEY (type, id)
);

CREATE TABLE A
(
    type SMALLINT,
    id   INTEGER,
    PRIMARY KEY (type, id),
    FOREIGN KEY (type, id) REFERENCES BC (type, id)
);
© www.soinside.com 2019 - 2024. All rights reserved.