3

请看下面的数据库设计:

create table Person (id int identity, InvoiceID int not null) 
create table Invoice (id int identity, date datetime)

目前所有人都有一个invoiceIDie the InvoiceIDis not null

我想扩展数据库,以便某些人没有Invoice. 最初的开发者讨厌空值并且从不使用它们。我想保持一致,所以我想知道是否有其他模式可以用来扩展数据库以满足这一要求。如何在不使用空值的情况下解决这个问题?

请注意,以上两个表格仅用于说明目的。它们不是实际的表。

4

4 回答 4

5

NULL 通常是数据库和编程中非常重要的特性。它与为零或任何其他值显着不同。它最常用于表示没有价值(尽管它也可以表示未知价值,但较​​少用作解释)。如果有些人没有发票,那么您应该真正允许 NULL,因为这与您想要的 Schema 匹配

于 2012-12-14T19:50:26.307 回答
3

正如其他一些答案所建议的那样,在避免空值的同时表示可选关系的唯一方法是使用另一个表。然后,给定人员的行不存在表示该人员没有发票。您可以通过将 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 的内容。

于 2012-12-14T20:17:53.247 回答
3

一种常见的模式是将该关联存储在单独的表中。

人员:Id 发票:Id Assoc:person_id, assoc_id

然后,如果一个人没有发票,那么您根本就没有行。这种方法还允许一个人拥有多个发票 ID,这可能是有意义的。

于 2012-12-14T19:50:24.197 回答
1

您需要将发票/人员关系移动到另一个表。你最终得到

create table Person (id int person_identity) 
create table PersonInvoice (id int person_id, InvoiceID int not null)  
create table Invoice (id int identity, date datetime)

对于某些数据库,您需要这个以允许 InvoiceId 作为外键,因为有些数据库不允许在外键中使用 NULLS。

如果一个人只能拥有一张发票,那么 PersonInvoice 可以对 person_id 以及两列一起具有唯一约束。您还可以通过向 invoiceID 字段添加唯一约束来强制发票只有一个人。

于 2012-12-14T19:55:47.340 回答