外键 NULL 与外键到空字符串

use*_*760 4 postgresql foreign-key database-design unique-constraint

这是一个药品目录表。有些有药品品牌,有些是通用的(即他们永远不会有品牌信息)

CREATE TABLE medicine (
   id serial PRIMARY KEY,
   name text NOT NULL,
   brand_id integer
   CONSTRAINT brand_fk FOREIGN KEY (brand_id) REFERENCES brand (id)       
);

CREATE TABLE brand (
  id serial PRIMARY KEY,
  name text NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

对于存储仿制药,例如abc& xyz,有两种选择:

  1. 使用 NULL 作为外键 brand_id

    INSERT INTO medicine (name, brand_id) VALUES ('abc', NULL)
    INSERT INTO medicine (name, brand_id) VALUES ('xyz', NULL)

  2. 在品牌名称中仅插入 1 个空字符串,并将其用于所有仿制药的 Brand_id

    INSERT INTO brand (id, name) VALUES (1, '')
    INSERT INTO medicine (name, brand_id) VALUES ('abc', 1)
    INSERT INTO medicine (name, brand_id) VALUES ('xyz', 1)

从我在 StackExchange 上读到的内容来看,这似乎1是执行此操作的一般方法。但是,如果我想要一个关于药物名称和品牌 ID 的唯一索引,我将不得不使用部分索引(即分别为brand_id IS NULL& 的2 个索引brand_id is NOT NULL)。

如果我采用第二种方法,我可以用一个索引来实现它。

这些方法中的任何一种是否还有其他优点/缺点。我觉得第二种方法是非常规的,以后可能会发现一些麻烦。

PS我已经使用药物的例子来说明我的查询,但我想纯粹从数据库的角度来理解解决方案的技术优点,即不讨论哪种方法更适合医学示例。

Erw*_*ter 7

答案在于你的问题的含糊不清:

但是,如果我想要一个关于医学的唯一索引name& brand_id...

您实际上并不想要“唯一索引”。您想强制执行某些规则。唯一索引是达到目的的手段;一个工具。问题是:你到底想要什么?

您是否希望只有一个name带有未知品牌的 a 实例?还是可以有多个实例?这取决于“未知”或“缺失”或“空”或NULL应该对您意味着什么。

NULL 的规范含义是“未知”。我们根本不知道,这里发生了什么,它可以是任何东西,包括任何东西''字符串类型中的空(),0数字类型中)。

如果您想允许一个通用品牌,请在 中包含一个条目brand,将其称为“通用”或“ ACME ”或其他任何名称。我喜欢将 id 值0用于这样一个包罗万象的条目。

然后你的唯一索引或约束正在做它应该做的事情: Allow only one instance of (name, brand_id)in the table medicine。但是(name, NULL)仍然可以使用多个条目。设置brand_id NOT NULL也一样,如果你不希望出现这种情况。

最佳解决方案还取决于您的设置的典型查询和详细信息。请务必准确记录NULL / empty / 0 的含义以及您选择这样设计的原因。在您实施它的那一刻,它可能看起来非常清晰,但稍后可能会令人困惑。

我在您引用的答案中添加了另一个链接: