标准使用“ Z”而不是NULL来表示丢失的数据?


76

除了是否应使用NULL之外,我还负责一个现有数据库,该数据库使用NULL表示“丢失或从未输入”数据。它不同于空字符串,它表示“用户设置了该值,并且他们选择了'空'”。

该项目的另一个承包商坚决主张“对于我来说不存在NULL;我从不使用NULL,并且任何人都不应使用NULL”。但是,令我困惑的是,由于承包商的团队确实承认“缺少/从未输入”和“故意空着或由用户指示为未知”之间的区别,因此他们在整个代码和存储过程中使用单个字符“ Z”表示“缺少/从未输入”,在整个数据库的其余部分中的含义与NULL相同。

尽管我们共享的客户要求更改此设置,而我也支持此要求,但是该团队将其称为比我更先进的DBA中的“标准做法”。他们不愿意仅根据我的无知请求更改为使用NULL。那么,有人可以帮助我克服我的无知吗?在SQL专家中,是否有任何标准或一小群人,甚至是一个大声的提倡使用“ Z”代替NULL的人?

更新资料

我有承包商的回应要补充。当客户要求删除特殊值以允许无数据列中的NULL时,他说的是这句话:

基本上,我设计数据库时要尽可能避免NULL。这是基本原理:

不需要在字符串[VARCHAR]字段中使用NULL,因为空(零长度)字符串会提供完全相同的信息。

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

日期字段中的NULL会很容易导致日期计算复杂化。例如,在计算日期差异(例如[RecoveryDate]和[OnsetDate]之间的天数差异)的逻辑中,如果一个或两个日期为NULL,则逻辑将爆炸-除非为两个日期都明确允许为NULL。那是额外的工作和额外的处理。如果[RecoveryDate]和[OnsetDate]使用“默认”或“占位符”日期(例如“ 1/1/1900”),则数学计算可能会显示“异常”值-但日期逻辑不会爆炸。

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

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

这似乎证实了对该问题的大部分消极反应。不是使用公认的6NF方法来设计NULL,而是使用特殊值来“尽可能避免NULL”。我以开放的态度发表了这个问题,很高兴我了解到更多有关“空值有用/空值很邪恶”的辩论,但是现在我很乐意将“特殊值”方法标记为完全废话。

空(零长度)字符串将提供完全相同的信息。

不,不是。在我们正在修改的现有数据库中,NULL表示“从未输入”,空字符串表示“输入为空”。

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

是的,但是成千上万的开发人员已经犯下了数千次错误,而且避免这些错误的教训和警告也广为人知并记录在案。如此处所述:无论您接受还是拒绝NULL,缺失值的表示都是一个已解决的问题。无需仅仅因为开发人员不断犯下易于克服(且易于识别)的错误而发明新的解决方案。


作为一个脚注:我已经成为DBE和开发人员已有20多年了(对于我来说,足够时间了解数据库工程师和数据库管理员之间的区别)。在我的整个职业生涯中,我一直都处于“ NULL是有用的”阵营,尽管我知道几个非常聪明的人不同意。我对“特殊价值”方法非常怀疑,但是对“如何避免以正确方式避免NULL”的学术知识不够扎实。我一直喜欢学习新事物,而且20年后我仍然有很多东西要学习。感谢所有为此做出有益讨论的人。


60
存在NULL来启用三元逻辑,这对于在没有完整信息的情况下保持引用完整性是必要的-我将对任何坚决反对它们的DB专家称呼为完全和完全BS!
gordy 2011年

17
完全没有听说过这种做法。
卡尔文·艾伦

14
承包商是否也为数值数据提出了替代NULL?
Andriy M,

14
@Andriy:这很容易解决,所有专家都将数字存储在字符字段中,并根据需要进行强制转换(使用Z形检查!)。哦,等等,我在错误的网站上
亩太短

12
我怀疑这名承包商一次企图执行,WHERE Column = NULL并且对为什么他没有得到任何结果感到困惑。
迈克·卡伦

Answers:


104

解雇您的承包商。

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

我实际上认为使用'Z'或任何其他占位符会更糟。您仍然需要代码来检查“ Z”。但是您还需要证明“ Z”并不意味着“ Z”,而是其他含义。并且您必须确保阅读了此类文档。然后,如果“ Z”成为有效数据,会发生什么?(例如字段的缩写?)

从根本上讲,即使不争论NULL vs'Z'的有效性,我也会坚持要求承包商遵守贵公司内而不是他公司内的标准惯例。在替代标准实践环境中建立他的标准实践会引起混乱,维护开销,误解,最终会增加成本和错误。


编辑

在某些情况下,我认为使用NULL替代方法是有效的。但是只有这样做才能减少代码,而不是创建需要考虑的特殊情况。

例如,我已将其用于日期绑定数据。如果数据在开始日期和结束日期之间有效,则可以通过不使用NULL值来简化代码。取而代之的是,空开始日期可以替换为“ 1900年1月1日”,而空结束日期可以替换为“ 2079年12月31日”。

这仍然可以改变行为,而应谨慎使用:

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

这等效于重新构造抽象,以使所有属性始终可以具有有效值。它与将特定含义隐式编码为任意选择的值明显不同。

仍然,解雇承包商。


21
向我+1;现场:“我实际上是说使用'Z'或任何其他占位符会更糟。您仍然需要代码来检查'Z'。但是您还需要证明'Z'并不意味着'Z',这意味着别的东西。”
米奇·

20
我们需要一个特殊的值-不能为NULL,因为NULL是邪恶的-来表示丢失的数据。与所有其他值(甚至可能与自身)不同的东西(因为不能将两个未知数等同,因为它们是未知数)。显然,某些列对此值没有意义,因此应禁止使用。为了使事情变得容易,我们需要像IS UNKNOWN或IS NOT UNKNOWN这样的特殊运算符。
迈克·卡伦

5
承包商通常会从丰富的经验中获得好的建议,但仅仅是因为有时会发生这种情况,并不意味着您就必须在建议的危险悬崖上跟随羊群。通知他们您是数据库的主人和所有者:开发将按照规定进行:遵从或终止。
wallyk 2011年

2
如果用户输入Z,则显然您存储ZZ。如果他们输入ZZ,则存储ZZZ,依此类推。这要求您将所有列的字符大一个,但这不应该成为问题。
Chas。欧文斯(Owens)

2
通常向我+1-但特别是在编辑中,因为它可以保存多少代码,所以可以在日期范围(最小日期/最大日期)中使用围栏帖子值有意义-特别是如果您必须比较/检查日期范围中的重叠。在这些情况下,最小日期表示“一直以来”,最大日期表示“直到永远”,这与NULL表示“不确定”或“无关紧要”不同。
乔尔·布朗

26

这很容易是我听过的最奇怪的意见之一。使用魔术值表示“无数据”而不是NULL意味着您必须对每一段代码进行后处理,以处理/丢弃“无数据” /“ Z”值。

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

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

如果name为NULL,则显然不会出现在第一个查询的结果中。更重要的是,它也不会显示在第二个查询结果中。NULL除了明确搜索NULL之外不匹配其他任何内容,例如:

select * from mytable where name is NULL;

当数据以Z为有效值时会发生什么?假设您要存储某人的中间名缩写?Zachary Z Zonkas是否会与那些没有中间名字首字母的人混为一谈?还是您的承包商会想出另一个神奇的方法来解决这个问题?

避免使用魔术值,这些魔术值要求您在数据库已经完全能够处理的代码中实现数据库功能。这是一个已解决且很好理解的问题,可能只是您的承包商从未真正理解过NULL的概念,因此避免使用它。


22

如果域允许缺少值,则使用NULL表示“未定义”是完全可以的(这就是它的作用)。唯一的缺点是必须编写消耗数据的代码以检查NULL。这就是我一直这样做的方式。

我从未听说过(或在实践中见过)使用“ Z”表示丢失的数据。至于“承包商在DBA中将其作为'标准做法'引用”,他能提供一些断言的证据吗?正如@Dems所提到的,您还需要证明'Z'并不意味着'Z':MiddleInitial列如何?

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


3
我认为这里的关键是“如果域允许缺失的值...”在我看来,有一个时间和一个地方支持使用NULL,一个时间和一个地方避免使用NULL,这需要一些智慧知道区别。我有时会感到,当初级DBE / DBA读取警告时,“如果不考虑它们的行为,NULL值可能在查询和计算中导致意外结果,”他的下意识的反应是标记所有NULL用法一样糟糕。一旦成为宗教观点,它在他的整个职业生涯中都会坚持下去。
鲍里斯·尼古拉耶维奇

1
忘记DELETE或UPDATE上的WHERE子句可能会对数据库造成损害=>永远不要使用它们。要么第一次就获取数据,要么在编辑器中打开表,然后自己做。
MatBailie 2011年

另外,请注意,OUTER联接产生NULL,因此不应使用。同上,向上滚动。
MatBailie 2011年

3
在某些标准中,Z代表GMT时区。
艾里克·罗伯逊

2
@Erick,这是不使用Z表示“无价值”的另一个原因。
鲍里斯·尼古拉耶维奇

17

即使您设法以某种方式向所有当前和将来的开发人员和DBA解释了有关“ Z”而不是NULL的信息,即使他们对所有内容进行了完美的编码,您仍然会混淆优化器,因为它不知道您已经完成了此工作。

使用特殊值表示NULL(它已经是特殊值表示NULL)将导致数据偏斜。例如,1900年1月1日发生了太多的事情,它将使优化器无法理解与您的应用程序真正相关的实际日期范围。

这就像经理决定的那样:“系领带不利于提高生产力,因此我们都将在自己的脖子上戴胶带。问题解决了。”


10
+1仅用于短语“使用特殊值表示NULL(它已经是特殊值表示NULL)”。。。
Mike Sherrill'Cat Recall'

我认为领结正是这样,用领带代替的领带被认为更适合这种场合……
Soren

9

我从未听说过广泛使用 'Z'代替NULL

(顺便说一句,我不是特别想与一个承包商合作,后者告诉您,他们和其他“高级” DBA的知识和能力都比您高得多。)

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

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

可能他会在此表中选择其他“魔术值”以避免与真实数据发生冲突'Z'?意味着您必须记住几个魔术值,以及在哪个地方使用哪个值……这比仅拥有一个魔术令牌要好得多NULL,并且必须记住随之而来的三值逻辑规则(和陷阱)吗?NULL至少是标准化的,与承包商的不同'Z'

我也不特别喜欢NULL,但是在各地随便用实际值(或更糟糕的是,有多个实际值)替换它几乎肯定比差NULL

让我在这里重复上面的评论以提高可见度:如果您想阅读一些严肃而又有充分根据NULL的反对者文章,我建议您写一篇简短的文章“如何在不使用NULL的情况下处理丢失的信息”(来自PDF的链接)第三宣言主页)。


4

原则上,对于正确的数据库设计,不需要任何内容​​。实际上,有许多不使用null的数据库设计,并且有很多非常好的数据库设计人员和整个开发团队设计了不使用null的数据库。通常,对向数据库添加空值时要谨慎,这是一件好事,因为它们不可避免地会在以后导致不正确或模棱两可的结果。

我还没有听说过使用Z作为占位符值而不是空值作为占位符值的“标准做法”,但是我希望您的承包商通常指的是哨兵值的概念,该有时在数据库设计中使用。但是,在不使用“虚拟”数据的情况下避免空值的更常见,更灵活的方法就是将它们设计出来。分解表,以便将每种事实类型记录在不具有“额外”未指定属性的表中。


1
我认为承包商的字面意思是使用“ Z”表示“不知道”。
wallyk 2011年

不幸的是,@ wallyk基本上是正确的:这不是学术或理论上的讨论。由于我自己是一名开发人员,因此我一直在遍历代码和存储过程。承包商使用文字字符“ Z”表示缺少/未输入的值。(实际上,即使在当前数据库设计中,“未知但已回答”的值也永远不会为NULL;对于文本字段,都使用空字符串,对于下拉列表,都使用字符“ U”表示用户确实回答了问题)答案是“我不知道。”)
Boris Nikolaevich

@dportas-我确实知道正确的数据库设计不需要使用null,但是由于我在“如果有正确的方法使用NULL,有时间和地方,”问题是要了解“ NoNULL”阵营中某人在良好的数据库设计中使用“ Z”是标准的,普通的还是任何人都提倡的。
鲍里斯·尼古拉耶维奇

3

回复承包商的评论

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

根据大多数其他答案,整个概念存在缺陷


4
虽然; 据我所知,在Oracle中,空字符串NULL。
MatBailie 2011年

1

虽然我从未见过'Z'是表示空值的魔术值,但我曾见过'X'用来表示一个尚未填写的字段。也就是说,我只在一个地方看到过,并且我的界面它不是一个数据库,而是一个XML文件……所以我不准备使用此参数作为惯例。

请注意,我们确实必须专门处理“ X”,并且正如Dems所提到的,我们必须对其进行记录,并且人们对此感到困惑。在我们的辩护中,这是由外部供应商强加给我们的,而不是我们自己做的事情!


对于存储使用char字段“ X”而不是“”(空格)检查的复选框选择的数据库,这将非常令人困惑。我希望反物质和物质不要混入同一数据库中。
wallyk

我认为这没有获得任何投票,因为它与原始的数据库设计问题没有直接关系,但是我至少必须说,即使这种“切向”的回答也只能强调承包商方法的荒谬性。(此外,我认为从现在开始,“无投票权”应替换为“ Z”。)
Boris Nikolaevich

这个问题的唯一答案。
达朱
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.