正如其他一些答案所建议的那样,在避免空值的同时表示可选关系的唯一方法是使用另一个表。然后,给定人员的行不存在表示该人员没有发票。您可以通过将 person_id 设置为主键或唯一键来强制此表和 Person 表之间的 1:1 关系:
CREATE TABLE PersonInvoice (
person_id INT NOT NULL PRIMARY KEY,
invoice_id INT NOT NULL,
FOREIGN KEY (person_id) REFERENCES Person(id),
FOREIGN KEY (invoice_id) REFERENCES Invoice(id)
);
如果要允许每个人拥有多张发票,则可以将主键声明为列对。
但是这个解决方案是为了满足您避免 NULL 的要求。这是人为的要求。NULL 在数据模型中具有合法的位置。
一些关系数据库理论家,如 Chris Date 避开 NULL,解释说 NULL 的存在会导致关系逻辑中出现一些令人不安的逻辑异常。对于这个阵营来说,如上所示的没有一行是表示缺失数据的更好方法。
但其他理论家,包括撰写关系理论开创性论文的 EF Codd,承认占位符的重要性,占位符表示“未知”或“不适用”。Codd 甚至在 1990 年的一本书中提出 SQL 需要两个占位符,一个用于“缺失但适用”(即未知),另一个用于“缺失但不适用”。
对我来说,我们在某些方面使用 NULL 时看到的异常情况就像我们在算术中除以零时看到的未定义结果。解决方案是: 不要那样做。
但我们当然不应该使用任何非 NULL 值,如 0 或 ''(空字符串)来表示缺失数据。同样,我们不应该使用 NULL,就好像它是一个普通的标量值一样。
我在我的书SQL Antipatterns: Avoiding the Pitfalls of Database Programming 的“对未知的恐惧”一章中写了更多关于 NULL 的内容。