请查看下面的数据库设计:
create table Person (id int identity, InvoiceID int not null)
create table Invoice (id int identity, date datetime)
目前所有人都有invoiceID
,即InvoiceID
为not null
。
我想扩展数据库,以便某些人没有Invoice
。原始开发人员讨厌空值而从不使用它们。我希望保持一致,所以我想知道是否有其他模式可用于扩展数据库以满足此要求。如何在不使用空值的情况下接近它?
请注意,上面的两个表格仅供参考。它们不是真正的表格。
答案 0 :(得分:5)
NULL通常是数据库和编程中非常重要的特性。它与零或任何其他值明显不同。它最常用于表示没有价值(虽然它也可能意味着未知的价值,但这不太用作解释)。如果有些人没有发票,那么你应该真正允许NULL,因为它符合你想要的Schema
答案 1 :(得分:3)
一种常见的模式是将该关联存储在单独的表中。
人:Id 发票:我 Assoc:person_id,assoc_id
然后,如果一个人没有发票,你根本就没有一行。这种方法还允许一个人拥有多个可能有意义的发票ID。
答案 2 :(得分: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的存在会导致关系逻辑中出现一些令人不安的逻辑异常。对于这个阵营,如上所示缺少一行是表示缺失数据的更好方法。
但其他理论家,包括编写关于关系理论的开创性论文的E. F. Codd,承认占位符的重要性意味着“不知道”或“不适用”。 Codd甚至在1990年的一本书中提出SQL需要两个占位符,一个用于“缺失但适用”(即未知),另一个用于“缺失但不适用”。
对我来说,当我们以某种方式使用NULL时,我们看到的异常就像我们在除以零时在算术中看到的未定义结果。解决方案是:不要那样做。
但当然我们不应该使用任何非NULL值(如0或''(空字符串)来表示缺少的数据。同样,我们不应该使用NULL,就像它是普通的标量值一样。
我在我的书SQL Antipatterns: Avoiding the Pitfalls of Database Programming中标题为“恐惧未知”的章节中写了更多关于NULL的内容。
答案 3 :(得分: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字段添加唯一约束来强制为发票设置单个人。