在任何数据库管理系统(DBMS)中,都可以将特定的数据项标记为“空值”(null)。空值代表“不存在值”的存在、值的不存在,或者……什么都没有。
这听起来有点像自相矛盾,一个空的值,但事实就是如此。每个DBMS都有自己对空值的支持实现,因此它用来向你传达“空值”的方式可能有所不同。例如,与某个数据元素关联的可能是一组位标志,其中一个位是“我是空值”标志。由于每个DBMS都有自己的实现方式,因此不应认为使用空值能大幅节省空间。空间可能被节省,也可能节省不多。
但空值并不能解释属性为何没有值,这就是混淆所在。通常认为,如果属性为空,可能意味着该值因某种原因不适用于当前情境。或者,可能是我们的数据收集工作未能成功。
可能存在一个本应存储在该数据库列中的值,但我们目前尚不清楚该值具体是什么。在处理涉及可能为空值属性的逻辑运算时,我们的逻辑会失效。该属性是否等于、大于或小于某个特定值?
当数据项为空值时,答案既不是真也不是假。答案是“我不知道”。常规真值表评估真与假的组合,因此我们甚至没有指南来回答评估真/假/未知所需的三值逻辑。
一些数据库管理系统(DBMS)进一步陷入这种不合逻辑的泥潭,声称长度为零的可变长度字符串列与空值完全不同。显然,这些数据库管理系统认为还存在另一种特殊的“无”。最终,当在查询中使用可空列作为过滤条件时,数据可能以意想不到的方式返回,例如,所有空值行要么被排除,要么被包含,具体取决于数据库管理系统。
可以通过将可能为空的列拆分到独立的表中来设计数据库模式,以最小化甚至消除空值。功能上,这些表类似于超类型/子类型结构。只有当某列或列组存在数据时,这些“子类型”表中才会存在行。这样,数据库就不会存储空值。然而,用户仍可通过外连接从这些表中创建查询,且结果可能包含空值。
数据库管理系统或数据平台可能提供多种与空值相关的运算符和函数。熟练的数据用户将学会根据数据使用需求选择并运用这些功能。
在数据仓库早期阶段,许多数据建模师对空值预防极为关注。常见策略是定义空值替代值以替代空值。例如,名称可能包含“Unknown”,代码可能包含“?”,开始日期可能是“1900/01/01”,结束日期可能是“9999/12/31”,等等。通过这种方式,所有不一致的空值逻辑都被完全规避。
数据库行业中仍有一部分人从哲学上反对使用空值,他们反对空值的原因确实显而易见——查询逻辑不一致,以及不明确出现空值的含义。
但空值已经存在,我怀疑它们在短期内甚至永远都不会被废弃。因此,在使用空值时要谨慎,尽可能避免使用,并确保数据使用者知道如何正确处理空值以满足其数据需求。
作者:Todd Schraml