转化为正常形式

Transforming into Normal Form

有区域、化身和区域实例。头像必须属于每个区域的零个或一个实例。

CREATE TABLE zones (
    id SERIAL NOT NULL PRIMARY KEY,
    name VARCHAR NOT NULL,
    ...
);

CREATE TABLE avatars (
    id SERIAL NOT NULL PRIMARY KEY,
    ...
);

CREATE TABLE instances (
    id SERIAL NOT NULL PRIMARY KEY,
    zone_id INTEGER REFERENCES zones NOT NULL,
    ...
);

CREATE TABLE avatar_instances (
    avatar_id INTEGER REFERENCES avatars NOT NULL,
    zone_id INTEGER REFERENCES zones NOT NULL,
    instance_id INTEGER REFERENCES instances NOT NULL,
    PRIMARY KEY(avatar_id, zone_id)
);

我对上面的架构不满意,因为 avatar_instances 中每条记录中的 zone_id 必须与相应 instances 行中的 zone_id 一致.

理想情况下,我想要 avatar_instances 上的唯一索引,它“到达”instances table 的内部以查看 instances.zone_id

例如

CREATE TABLE avatar_instances (
    avatar_id INTEGER REFERENCES avatars NOT NULL,
    instance_id INTEGER REFERENCES instances NOT NULL,
    PRIMARY KEY(avatar_id, instance.zone_id)
);

如何将此模式转换为第 N 范式,同时保留 'each avatar must belong to zero or one instance for each zone' 的限制?

创建唯一并添加引用唯一的复合 FK。

CREATE TABLE instances (
    id SERIAL NOT NULL PRIMARY KEY,
    zone_id INTEGER REFERENCES zones NOT NULL,
    UNIQUE (zone_id, id)
);

CREATE TABLE avatar_instances (
    avatar_id INTEGER REFERENCES avatars NOT NULL,
    zone_id INTEGER NOT NULL,
    instance_id INTEGER NOT NULL,
    CONSTRAINT fk_ai2i FOREIGN KEY (zone_id, instance_id) REFERENCES instances (zone_id, id),
    PRIMARY KEY(avatar_id, zone_id)
);

如果头像必须属于每个区域的零个或一个实例,则在 avatar_instances.instance_id 中允许空值。