1

我有两张桌子 - 第一张是地方,第二张是位置。地点可以有零个或多个位置。Place PK 是 id,location PK 是两个组件键 place_id + id。

在此处输入图像描述

在第三张桌子(例如发票)中,我可以找到没有任何位置的地方。

问题是:如何在发票表中设置FK?

  1. 我不能只使用 place.id 作为 FK,因为我想知道位置。
  2. 如果我使用由 place_id + id 列组成的位置 PK - 那么与表位置的关系不一致 - 某些地方可以有 0 位置。

因此,主要问题是某些地方可以有 0 个位置。

是的,我可能会在位置表中设置代理 PK,并将 place_id FK、location_id FK 设置为 NULL。但是,要求是位置和位置键是自然的(基于公司组织结构)。第二个想法是进行一对一/多关联,并将位置 id 值 0 用于具有零位置的位置,并在用户界面中隐藏该位置。实际上,然后我需要为每个地方放置位置 0(无位置)。

谢谢。

4

1 回答 1

2

您应该能够简单地将这两个 FK“合并”在一起:

在此处输入图像描述

CREATE TABLE invoice (
    id INT PRIMARY KEY,
    place_id INT NOT NULL,
    location_id INT NULL,
    FOREIGN KEY (place_id) REFERENCES place (id),
    FOREIGN KEY (place_id, location_id) REFERENCES location (place_id, id)
);

DBMS 将忽略具有至少一个 NULL 的 FK:

  • place_id不是 NULL,因此第一个 FK 将始终有效。
  • 如果location_id为 NULL,则将忽略第二个 FK。

您可以在这个SQL Fiddle中使用它。

(事实上​​,自然键的存在使您能够做到这一点 - 如果location有一个代理键,您不能保证两个 FK 指向同一个place。)


在不太可能的情况下,您的 DBMS 会以一种有趣的方式处理 NULL,因此不会忽略带有 NULL 的 FK,您可以将这两个 FK 完全分开,并使用 CHECK 确保它们属于同一位置:

CREATE TABLE invoice (
    id INT PRIMARY KEY,
    place_id INT NOT NULL,
    location_place_id INT NULL,
    location_id INT NULL,
    FOREIGN KEY (place_id) REFERENCES place (id),
    FOREIGN KEY (location_place_id, location_id) REFERENCES location (place_id, id),
    CHECK (place_id = location_place_id)
);
于 2012-05-16T10:46:33.993 回答