有一种观点认为在关系数据库中不应该允许空值.也就是说,表的属性(列)不应该允许空值.来自软件开发背景,我真的不明白这一点.似乎如果null在属性的上下文中有效,那么应该允许它.这在Java中非常常见,其中对象引用通常为null.没有广泛的数据库经验,我想知道我是否在这里遗漏了一些东西.
从数据库规范化的角度来看,负面观点是否定的.这个想法是,如果一个值可以是空的,那么你真的应该把它拆分成另一个稀疏表,这样你就不需要没有值的项的行.
这是确保所有数据有效和有价值的努力.
在某些情况下,有一个空字段是有用的,特别是当你想出于性能原因而想要避免另一个连接时(尽管如果数据库引擎设置正确,这应该不是问题,除非在特殊的高性能方案中.)
-亚当
反对null的一个论点是它们没有明确定义的解释.如果字段为null,则可以将其解释为以下任何一种:
值为"Nothing"或"Empty set"
对于该领域没有任何价值.
价值未知.
该值尚未输入.
该值为空字符串(对于不区分空值和空字符串的数据库).
一些特定于应用程序的含义(例如,"如果值为null,则使用默认值.")
发生错误,导致该字段具有空值,而实际上不应该.
一些模式设计者要求所有值和数据类型都应具有明确定义的解释,因此空值很差.
空标记很好.真的,他们是.
这取决于.
只要你理解为什么你NULL
在数据库中允许s(需要按列进行选择)以及你将如何解释,忽略或以其他方式处理它们,它们就没问题了.
例如,一个专栏NUM_CHILDREN
- 如果你不知道答案你会怎么做 - 它应该是NULL
.在我看来,这个列的设计没有其他最佳选择(即使你有一个标志来确定NUM_CHILDREN
列是否有效,你仍然必须在这一列中有一个值).
另一方面,如果你不允许NULL
s并且对某些情况(而不是标志)有特殊的保留值,比如-1对于真正未知的子节点数,你必须以类似的方式解决这些问题,公约条款,文件等
因此,最终必须通过约定,文档和一致性来解决这些问题.
另一方面,正如Adam Davis在上述答案中明显支持的那样,将列规范化为稀疏(或者不是如此稀疏,在NUM_CHILDREN
大多数数据具有已知值的示例或任何示例的情况下)表,同时能够消除所有NULL,在一般实践中是不可行的.
在许多属性未知的情况下,为每个列连接到另一个表是没有意义的,这可能允许NULL
更简单的设计.连接的开销,主键的空间要求在现实世界中没有多大意义.
这让人想起通过添加基数列可以消除重复行的方式,同时它理论上解决了没有唯一键的问题,实际上有时是不可能的 - 例如,在大规模数据中.然后,纯粹主义者迅速建议替代PK,但是从关系理论的角度来看,无意义的代理可以构成关系(表格)中元组(行)的一部分的想法是可笑的.
使用NULL有几种不同的异议.一些反对意见是基于数据库理论.从理论上讲,理论与实践之间没有区别.在实践中,有.
确实,完全规范化的数据库可以在没有NULLS的情况下相处.任何必须省略数据值的地方都是可以省去整行但不丢失信息的地方.
实际上,将表分解到这个程度并没有什么用处,并且对数据库执行简单CRUD操作所需的编程变得更加繁琐且容易出错,而不是更少.
有些地方使用NULLS会导致问题:基本上这些问题围绕着以下问题:缺失数据究竟意味着什么?真正传达的所有NULL都是在给定字段中没有存储的值.但推理应用程序员从缺失的数据中抽取有时是不正确的,这会导致很多问题.
由于各种原因,某个位置可能会丢失数据.以下是一些:
在此上下文中,数据不适用.例如,配偶一个人的名字.
数据输入表单的用户将字段留空,并且应用程序不需要字段中的条目.
数据从其他一些数据库或文件复制到数据库,并且源中缺少数据.
在外键中编码可选关系.
空字符串存储在Oracle数据库中.
以下是关于何时避免使用NULLS的一些指导原则:
如果在正常预期编程过程中,查询编写者必须编写大量ISNULL,NV,COALESCE或类似代码,以便将有效值替换为NULL.有时候,如果存储的是"现实",最好在商店时间进行替换.
如果计数可能会被关闭,因为计算了包含NULL的行.通常,只需选择count(MyField)而不是count(*)就可以避免这种情况.
这里有一个地方,你可以更好地习惯NULLS,并相应地编程:每当你开始使用外连接时,如LEFT JOIN和RIGHT JOIN.外连接背后的整点与内连接不同,是在缺少某些匹配数据时获取行.缺失的数据将作为NULLS提供.
我的底线:不理解它就不要理论.但要学会何时偏离理论以及如何遵循理论.
将NULL用于数据字段没有任何问题.将键设置为null时必须小心.主键永远不应为NULL.外键可以为null,但您必须小心不要创建孤立记录.
如果某些内容"不存在",那么您应该使用NULL而不是空字符串或其他类型的标志.
而不是写出NULL的所有问题,以及三态与布尔逻辑等等 - 我将提供这个精辟的建议:
不要在列中允许NULL,直到您发现自己添加魔术值来表示丢失或不完整的数据.
既然你问这个问题,你应该非常小心你如何处理NULL.它有很多非常明显的缺陷.如有疑问,请勿使用NULL.
还有另一种选择,使用"N/A"或"N/K"或空字符串 - 一个单独的表.
例如,如果我们可能知道或不知道客户的电话号码:
CREATE TABLE Customer (ID int PRIMARY KEY, Name varchar(100) NOT NULL, Address varchar(200) NOT NULL); CREATE TABLE CustomerPhone (ID int PRIMARY KEY, Phone varchar(20) NOT NULL, CONSTRAINT FK_CustomerPhone_Customer FOREIGN KEY (ID) REFERENCES Customer (ID));
如果我们不知道电话号码,我们就不会在第二个表格中添加一行.
我会说绝对应该使用Nulls.没有其他正确的方法来表示缺乏数据.例如,使用空字符串表示缺少的地址行是错误的,或者使用0表示缺少的年龄数据项是错误的.因为空字符串和0都是数据.Null是表示这种情况的最佳方式.
不要通过使字段为NULL来低估您创建的复杂性.例如,以下where子句看起来会匹配所有行(位只能是1或0,对吧?)
where bitfield in (1,0)
但是如果位域是NULLable,它将会遗漏一些.或者采取以下查询:
select * from mytable where id not in (select id from excludetable)
现在,如果excludetable包含null和1,则转换为:
select * from mytable where id <> NULL and id <> 1
但是对于任何id值,"id <> NULL"都为false,因此这将永远不会返回任何行.这甚至可以吸引经验丰富的数据库开发人员.
鉴于大多数人都可以被NULL逮捕,我尽量避免使用它.
这是一个巨大的蠕虫,因为NULL可能意味着很多东西:
没有死亡日期,因为这个人还活着.
没有手机号码,因为我们不知道它是什么,甚至它是否存在.
没有社会安全号码,因为该人知道没有社会安全号码.
其中一些可以通过规范化来避免,其中一些可以通过该列中存在的值("N/A")来避免,其中一些可以通过使用单独的列来解释NULL的存在来缓解("N/K","N/A"等).
它也是一种蠕虫,因为找到它们所需的SQL语法与非空值的SQL语法不同,很难加入它们,并且它们通常不包含在索引条目中.
由于前一个原因,您将找到无法避免null的情况.
由于后一种原因,您仍应尽力减少它们的数量.
无论如何,始终使用NOT NULL约束来防止需要值的空值.
nulls的主要问题是它们具有特殊的语义,可以通过比较,聚合和连接产生意外的结果.
没有任何东西等于null,并且任何东西都不等于,大于或小于null,因此如果要进行任何批量比较,则必须将空值设置为占位符值.
这也是可能在连接中使用的复合键的问题.如果自然键包含可空列,您可能需要考虑使用合成键.
空值可以不计数,这可能不是你想要的语义.
您可以加入的列中的空值将消除内部联接中的行.一般来说,这可能是期望的行为,但它可以为进行报告的人打下大象陷阱.
null还有其他一些细微之处.Joe Celko的SQL for Smarties有一整章关于这个主题,是一本好书,无论如何都值得一读.空值是一个很好的解决方案的地方的一些例子是:
连接实体可能存在或不存在的可选关系.Null是表示外键列上的可选关系的唯一方法.
您可能希望使用null以退出计数的列.
可能存在或不存在的可选数字(例如货币)值.在数字系统中没有"未记录"的有效占位符值(特别是在零是合法值的情况下),因此null实际上是唯一的好方法.
您可能希望避免使用空值的地方的一些示例,因为它们可能会导致细微的错误.
代码字段上的"Not Recorded"值,对参考表使用FK.使用占位符值,因此在对数据库执行查询时,您(或某些随机业务分析师在轨道上)不会无意中从结果集中删除行.
没有输入任何内容的描述字段 - null string(''
)适用于此.这节省了必须将空值视为特殊情况.
报告或数据仓库系统上的可选列.对于这种情况,在维度中为"未记录"创建一个占位符行,并加入该行.这简化了查询,并与ad-hoc报告工具很好地配合使用.
同样,Celko的书是对这个主题的一个很好的对待.
关于普通形式的最好的事情是它们是指南和指南不应该被坚持遵守.当学术界与现实世界发生冲突时,你很少找到许多幸存的乙炔战士.
这个问题的答案是可以使用空值.只是评估您的情况并决定是否希望它们显示在表格中,或者如果您觉得空值与实际值的比率太高,则将数据折叠到另一个相关表格中.
正如朋友喜欢说的那样,"不要让完美成为善的敌人".想想伏尔泰也说过.8)