标准使用'Z'而不是NULL来表示缺失的数据?

在是否应该使用NULL的参数之外:我负责使用NULL表示“丢失或从未input”数据的现有数据库。 它与空string不同,意思是“用户设置了这个值,而且他们select了”空“。

项目的另外一个承包商坚定地坚持“不存在NULL,我从来不使用NULL,也不应该使用NULL”。 然而,让我感到困惑的是,由于承包商的团队确认了“缺less/从不进入”和“有意清空或由用户指示为未知”之间的区别,他们在其代码和存储过程中使用单个字符“Z”在整个数据库的其余部分表示“丢失/从不进入”,其含义与NULL相同。

尽pipe我们的共享客户已经要求改变这一点,而且我也支持这个请求,但是团队认为这是DBA中比我更先进的“标准实践”。 他们不愿意单独根据我的无知请求更改为使用NULL。 那么,谁能帮我克服我的无知? SQL专家中是否有任何标准或一小组个人,甚至是一个大声的提倡使用“Z”代替NULL的声音?

更新

我有一个承包商的回应补充。 以下是当客户要求删除特殊值以允许在没有数据的列中允许NULL时他所说的内容:

基本上,我devise的数据库,以尽可能避免NULL。 这是理由:

string[VARCHAR]字段中的NULL是不必要的,因为空(零长度)string提供完全相同的信息。

整数字段(例如,ID值)中的NULL可以通过使用永远不会出现在数据中的值来处理(例如,对于整数IDENTITY字段,则为-1)。

date字段中的NULL可能很容易造成date计算的复杂性。 例如,在计算date差异的逻辑(如[RecoveryDate]和[OnsetDate]之间的天数差异)中,如果一个或两个date都为NULL,则逻辑将爆炸 – 除非为两个date为NULL。 这是额外的工作和额外的处理。 如果[RecoveryDate]和[OnsetDate](例如“1/1/1900”)使用“default”或“placeholder”date,math计算可能会显示“exception”值 – 但date逻辑不会被炸毁。

传统上,NULL处理是开发人员在存储过程中犯错的区域。

在我作为DBA的15年中,我发现尽可能避免NULL。

这似乎validation了对这个问题的主要负面反应。 而不是应用可接受的6NF方法来deviseNULL,特殊值用于“尽可能避免NULL”。 我以开放的态度发表了这个问题,很高兴我对“NULL是有用的/ NULL是邪恶的”辩论有了更多的了解,但是现在我很舒服地将“特殊值”方法标记为完全无稽之谈。

一个空的(零长度)string提供完全相同的信息。

不,它不; 在我们正在修改的现有数据库中,NULL表示“从不input”,空string表示“input为空”。

传统上,NULL处理是开发人员在存储过程中犯错的区域。

是的,但成千上万的开发人员已经犯了数千次错误,而避免这些错误的经验教训和注意事项是已知的并且是有logging的。 正如这里所提到的那样:无论你接受还是拒绝NULL,缺失值的表示都是一个解决的问题 。 没有必要发明一种新的解决scheme,因为开发人员继续制造易于克服(易于识别)的错误。


作为一个脚注:我已经是DBE和开发人员20多年了(这当然有足够的时间让我知道数据库工程师和数据库pipe理员之间的差异)。 在我整个职业生涯中,我一直都是在“有用”的阵营,虽然我知道有几个非常聪明的人不同意。 我对“特殊价值”方法持怀疑态度,但对于“如何避免以正确方法行事”这一学者坚持不懈,坚持不懈。 我总是喜欢学习新东西,20年后我仍然有很多东西要学。 感谢所有为此作出贡献的人士提供有用的讨论。

解雇你的承包商。

好的,严重的是,这不是标准的做法。 这可以简单地看出来,因为我曾经使用过的所有RDBMS都实现了NULL,NULL的逻辑,在外键中考虑了NULL,在COUNT中的NULL等具有不同的行为,等等。

我实际上认为使用“Z”或其他任何地方持有者是更糟糕的。 你仍然需要检查“Z”的代码。 但是你也需要certificate'Z'不是'Z',这意味着别的东西。 你必须确保阅读这些文件。 那么如果'Z'成为一个有效的数据,会发生什么? (如初始字段?)

在基本的层面上,即使没有讨论NULL和Z的有效性,我也会坚持承包商是符合贵公司内部的标准惯例,而不是他的。 在一个具有其他标准实践的环境中制定他的标准实践将会导致混乱,维护费用,误解,最终增加成本和错误。


编辑

在我看来有些情况下,使用替代NULL是有效的。 但只有这样做才能减less代码,而不是创build需要考虑的特殊情况。

例如,我用它来表示date边界数据。 如果数据在开始date和结束date之间有效,则可以通过不具有NULL值来简化代码。 相反,NULL开始date可以replace为'01 Jan 1900',NULL结束date可以replace为'2079年12月31日'。

这仍然可以改变行为从可以预期的,所以应该谨慎使用:

  • WHERE end-date IS NULL不再提供仍然有效的数据
  • 你刚刚创build了自己的千年虫
  • 等等

这相当于改革抽象,使所有的属性总是有效的值。 它明显不同于将具体含义隐含编码为任意select的值。

不过,解雇承包商。

这很容易成为我听过的最奇怪的观点之一。 使用一个魔术值来表示“无数据”而不是NULL意味着你所拥有的每一段代码将不得不后处理结果来计算/放弃“无数据”/“Z”值。

NULL是特殊的,因为数据库在查询中处理它的方式。 例如,采取这两个简单的查询:

 select * from mytable where name = 'bob'; select * from mytable where name != 'bob'; 

如果name是NULL,那么显然不会显示在第一个查询的结果中。 更重要的是,它也不会出现在第二个查询结果中。 NULL不匹配NULL以外的显式search,如下所示:

 select * from mytable where name is NULL; 

当数据可能有Z值作为有效值时会发生什么? 假设你正在存储某人的中间名字? Zachary Z Zonkas会和那些没有中间名的人混在一起吗? 或者你的承包商会想出另外一个魔法值来处理这个问题?

避免需要在数据库已经完全能够处理的代码中实现数据库特性的魔术值。 这是一个很好解决的问题,也许你的承包商从来没有真正地理解NULL的概念,因此避免使用它。

如果域允许缺less值,那么使用NULL来表示'undefined'是完全正确的(这就是它的原因)。 唯一的缺点是必须写入消耗数据的代码来检查NULL。 这是我一直这样做的方式。

我从来没有听说过(或者在实践中)使用'Z'来表示缺失的数据。 对于“承包商把这个作为DBA之间的标准做法”,他能否提供一些这种断言的证据? 正如@Dems所提到的那样,你还需要certificate“Z”不代表“Z”: MiddleInitial列呢?

像Aaron Alton和其他人一样,我相信NULL值是数据库devise的一个组成部分,应该在适当的地方使用。

即使您以某种方式设法向所有当前和未来的开发人员和DBA解释有关“Z”而不是NULL的信息,并且即使它们完美地编码了所有内容,仍然会迷惑优化器,因为它不会知道您已经熟悉了。

使用一个特殊的值来表示NULL(这已经是一个表示NULL的特殊值)将导致数据中的偏斜。 例如在1900年1月1日发生了很多事情,它会抛出优化器能够理解真正与您的应用程序相关的实际date范围。

这就像一个经理人决定:“打领带不利于生产力,所以我们都会在我们的脖子上戴上胶带,问题解决了。

我从来没有听说过广泛使用'Z'作为NULL的替代品。

(顺便说一句,我不是特别喜欢和一个承包商一起工作,他们告诉你他们和其他“高级”DBA比你更有知识和更好。)

  +=================================+ | FavoriteLetters | +=================================+ | Person | FavoriteLetter | +--------------+------------------+ | 'Anna' | 'A' | | 'Bob' | 'B' | | 'Claire' | 'C' | | 'Zaphod' | 'Z' | +---------------------------------+ 

你的承包商如何解释最后一行的数据?

也许他会在这个表中select一个不同的“魔法值”,以避免与真实数据'Z'相冲突? 这意味着你必须记住几个魔法值,以及哪一个被用在哪里……这比只有一个魔法标记为NULL还要记住三值逻辑规则(和陷阱)更好? 至lessNULL是标准化的,不像承包商的'Z'

我也不是特别喜欢NULL ,但是在任何地方无意识地用实际值(或者更糟,具有几个实际值)代替它几乎肯定比NULL更差。

让我在这里重复我的上面的评论以获得更好的可见性:如果你想阅读一些严重的和反对NULL的人的基础,我会推荐短文“如何处理丢失的信息,而不使用NULL” (链接到PDF来自第三个宣言主页 )。

原则上没有要求正确的数据库devise的空值。 事实上,有大量的数据库devise时没有使用null,并且有很多非常好的数据库devise者和整个开发团队在不使用空值的情况下devise数据库。 一般来说,谨慎地向数据库中添加空值是一件好事,因为它们不可避免地导致以后不正确或模糊的结果。

我还没有听说过将Z称为“标准实践”作为占位符值而不是空值,但我期望您的承包商一般指的是哨兵值的概念,有时在数据库devise中使用。 但是,如果不使用“虚拟”数据,避免空值的一种更加普遍和灵活的方法就是简单地devise出来。 分解表,使每种types的事实都logging在没有“额外”,未指定属性的表中。

在答复承包商的意见

  • 空string<> NULL
  • 空string需要2个字节存储+偏移量读取
  • NULL使用null位图=更快
  • 身份并不总是从1开始(为什么浪费你的一半范围?)

整个概念在这里大多数其他答案是有缺陷的

虽然我从来没有见过“Z”作为表示null的魔法值,但是我看到“X”用来表示一个没有被填充的字段。也就是说,我只在一个地方见过这个字段,而我的接口因为它不是一个数据库,而是一个XML文件…所以我不会准备使用这个论点作为通常的做法。

请注意,我们必须特别处理'X',而且正如德姆斯所说,我们必须logging下来,人们对此感到困惑。 在我们的辩护中,这是由外部供应商强加给我们的,而不是我们自己制造的东西!