请查看下面的数据库设计:
create table Person (id int identity, InvoiceID int not null)
create table Invoice (id int identity, date datetime)
当前,所有人都具有invoiceID
,即InvoiceID
是not null
。
我想扩展数据库,使某些人没有Invoice
。最初的开发人员讨厌null,从不使用它们。我想保持一致性,所以我想知道是否有其他模式可以用来扩展数据库以满足这一要求。如何在不使用null的情况下实现这一点?
请注意,以上两个表格仅供说明。它们不是真正的桌子。
NULL在数据库和编程中是一个非常重要的特性。它与零或任何其他值有很大不同。它最常用于表示没有价值(尽管它也可以表示未知的价值,但很少用作解释)。如果有些人没有发票,那么你应该真正允许NULL,因为这与你想要的Schema 匹配
一种常见的模式是将该关联存储在一个单独的表中。
人员:Id发票:Id关联:person_id,Assoc_id
那么,如果一个人没有发票,你就根本没有一排。这种方法还允许一个人拥有多个发票id,这可能是有意义的。
在避免null的同时表示可选关系的唯一方法是使用另一个表,正如其他一些答案所建议的那样。如果给定人员没有一行,则表示该人员没有发票。您可以通过将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的存在会导致关系逻辑中一些令人不安的逻辑异常。对于这个阵营来说,缺少如上所示的行是表示缺失数据的更好方法。
但其他理论家,包括E.F.Codd,他写了一篇关于关系理论的开创性论文,承认占位符的重要性,占位符的意思是";未知";或";不适用"Codd甚至在1990年的一本书中提出,SQL需要两个占位符,一个用于";缺失但适用";(即未知),另一个表示"未知";缺失但不适用">
对我来说,当我们以某些方式使用NULL时,我们看到的异常就像我们在算术中除以零时看到的未定义结果一样。解决方案是:不要那样做。
但我们当然不应该使用任何非NULL值,如0或"(空字符串)来表示丢失的数据。同样,我们不应该像使用普通标量值一样使用NULL。
我在题为";对未知的恐惧;在我的书《SQL反模式第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作为外键,因为有些数据库不允许在外键中使用NULLS。
如果一个人只能有一张发票,那么PersonInvoice可以对person_id以及两列具有唯一约束。您还可以通过向invoiceID字段添加唯一约束来强制发票由一个人处理。