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

Bor*_*ich 76 sql null standards rdbms database-design

除了是否应该使用NULL之外的参数:我负责使用NULL表示"丢失或从未输入"数据的现有数据库.它与空字符串不同,这意味着"用户设置此值,并且他们选择'空'."

该项目的另一个承包商坚定地认为"对我来说不存在NULL;我从不使用NULL,其他任何人都不应该,"论证的一方.然而,令我感到困惑的是,由于承包商的团队确认"丢失/从未输入"和"故意空白或用户指示为未知"之间的区别,他们在整个代码和存储过程中使用单个字符"Z".在整个数据库的其余部分表示"缺少/从未输入",其含义与NULL相同.

虽然我们的共享客户要求更改此项,并且我已经支持此请求,但团队认为这是比我更先进的DBA中的"标准做法"; 他们不愿意根据我的无知请求单独更改为使用NULL.那么,任何人都可以帮助我克服自己的无知吗?在SQL专家中是否有任何标准或小组的个人,甚至是一个大声的声音,主张使用'Z'代替NULL?

更新

我得到了承包商的回复.以下是当客户要求删除特殊值以在没有数据的列中允许NULL时他说的话:

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

字符串[VARCHAR]字段中的NULL永远不是必需的,因为空(零长度)字符串提供完全相同的信息.

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

日期字段中的NULL很容易导致日期计算的复杂化.例如,在计算日期差异的逻辑中,例如[RecoveryDate]和[OnsetDate]之间的天数差异,如果一个或两个日期为NULL,逻辑将会爆炸 - 除非明确考虑两个日期为NULL.这是额外的工作和额外的处理.如果[RecoveryDate]和[OnsetDate]使用"default"或"placeholder"日期(例如,"1/1/1900"),则数学计算可能会显示"异常"值 - 但日期逻辑不会爆炸.

传统上,NULL处理是开发人员在存储过程中出错的一个领域.

在我担任DBA的15年中,我发现尽可能避免使用NULL.

这似乎证实了对这个问题的主要负面反应.不使用接受的6NF方法来设计NULL,而是使用特殊值来"尽可能避免使用NULL".我以开放的心态发布了这个问题,我很高兴我学到了更多关于"NULLs is useful/NULLs is evil"的讨论,但我现在很乐意将"特殊值"方法标记为完全无稽之谈.

一个空的(零长度)字符串提供完全相同的信息.

不,它没有; 在我们正在修改的现有数据库中,NULL表示"从未输入",空字符串表示"输入为空".

传统上,NULL处理是开发人员在存储过程中出错的一个领域.

是的,但成千上万的开发人员已经成功地做了数千次错误,并且已知并记录了避免这些错误的经验和警告.正如这里提到的:无论你是接受还是拒绝NULL,缺失值的表示都是一个解决的问题.没有必要发明新的解决方案只是因为开发人员继续做出易于克服(且容易识别)的错误.


作为一个脚注:我已经成为一名DBE和开发人员超过20年(这当然足以让我知道数据库工程师和数据库管理员之间的差异).在我的整个职业生涯中,我一直都在"NULLs是有用的"阵营,虽然我知道几个非常聪明的人不同意.我对"特殊价值观"的方法持怀疑态度,但对于"如何避免正确的方式"的学术问题却不够精通,无法做出坚定的立场.我一直喜欢学习新东西 - 20年后我还有很多需要学习的东西.感谢所有为此做出有益讨论的人.

Mat*_*lie 104

麻袋你的承包商.

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

我实际上认为使用'Z'或任何其他占位符更糟糕.您仍然需要代码来检查"Z".但你还需要记录'Z'并不意味着'Z',它意味着别的东西.您必须确保阅读此类文档.如果'Z'成为有效的数据,会发生什么?(如初始字段?)

在基本层面,即使没有讨论NULL与'Z'的有效性,我也会坚持认为承包商符合贵公司内部的标准做法,而不是他的.在具有替代标准实践的环境中制定他的标准实践将导致混淆,维护开销,误解,并最终增加成本和错误.


编辑

在我看来,有些情况下使用NULL的替代方法是有效的.但只有这样做才能减少代码,而不是创建需要计算的特殊情况.

例如,我已经将它用于日期绑定数据.如果数据在开始日期和结束日期之间有效,则可以通过不使用NULL值来简化代码.相反,NULL开始日期可以用'01 Jan 1900'替换,NULL结束日期可以用'31 Dec 2079'替换.

这仍然可以改变预期的行为,因此应谨慎使用:

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

这相当于改进抽象,使得所有属性总是具有有效值.它与将特定含义隐式编码为任意选择的值明显不同.

仍然,解雇承包商.

  • 来自我的+1; 现场观点:"我实际上会争辩说使用'Z'或任何其他占位符更糟糕.你还需要代码来检查'Z'.但你还需要记录'Z'并不意味着'Z',它意味着别的东西." (21认同)
  • 我们需要的是一个特殊的值 - 不是NULL,因为NULL是邪恶的 - 来表示缺少的数据.一些与所有其他价值观不同的东西,甚至可能来自它自己(因为,两个未知数不能仅仅因为它们未知而等同).有些列显然对这个值没有意义,因此应该被禁止.为了方便起见,我们需要特殊的操作符,例如IS UNKNOWN或IS NOT UNKNOWN. (20认同)
  • 承包商经常从深刻的经验中得到很好的建议,但仅仅因为*有时*发生,并不意味着你必须跟随绵羊超过推荐的危险悬崖.告知他们您是数据库的主人和所有者:开发将按照规定:遵守或死亡. (5认同)
  • 如果用户输入Z,那么显然你存储ZZ.如果他们进入ZZ,则存储ZZZ,依此类推.这要求您将所有列的一个字符放大,但这应该不是问题. (2认同)
  • 一般来说+1来自我 - 但特别是对于编辑,因为它可以节省多少代码,因为它可以节省多少代码 - 特别是如果你需要比较/检查它的日期范围(最小日期/最大日期)使用fence post值是有意义的在日期范围内重叠.在这些情况下,最小日期表示"从始至终",最大日期表示"直到永远",这与NULL不同,意思是"不确定"或"不关心". (2认同)

unp*_*nic 26

这很容易成为我听过的最奇怪的观点之一.使用魔术值来表示"无数据"而不是NULL意味着您拥有的每一段代码都必须对结果进行后处理以记录/丢弃"无数据"/"Z"值.

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

select * from mytable where name = 'bob';
select * from mytable where name != 'bob';
Run Code Online (Sandbox Code Playgroud)

如果name永远为NULL,它显然不会出现在第一个查询的结果中.更重要的是,它不会出现在第二个查询结果中.NULL与显式搜索NULL之外的任何内容都不匹配,如:

select * from mytable where name is NULL;
Run Code Online (Sandbox Code Playgroud)

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

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


Mit*_*eat 22

如果域允许缺少值,那么使用NULL来表示'undefined'是完全可以的(这就是它的用途).唯一的缺点是必须编写消耗数据的代码来检查NULL.这是我一直这样做的方式.

我从未听说过(或在实践中看到过)使用'Z'来表示缺失的数据.至于"承包商将此称为"DBA中的'标准做法'",他能否提供一些证据来证明这一说法?正如@Dems所提到的,你还需要记录'Z'不代表'Z':MiddleInitial列怎么样?

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

  • +1:很好的链接:) [我仍然说要解雇承包商.] (3认同)
  • 我认为这里的关键是"如果域允许缺少值..."在我看来,有一个时间和地点支持使用NULL,以及避免它们的时间和地点,它需要一些智慧知道差异.我有时会感觉到,当一个初级DBE/DBA读到一个警告时,"如果你不考虑他们的行为,NULL值会导致查询和计算出现意外结果",他的下意识反应是标记所有NULL使用一样糟糕.一旦它成为一种宗教信仰的观点,它就会在他职业生涯的剩余时间里坚持下去. (3认同)
  • Z用于表示某些标准中的GMT时区. (3认同)
  • @Erick,这是不使用Z意味着"没有价值"的另一个原因. (2认同)

WW.*_*WW. 17

即使你以某种方式设法向所有当前和未来的开发人员和DBA解释"Z"而不是NULL,即使他们完美地编码所有内容,你仍然会混淆优化器,因为它不会知道你已经煮熟了.

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

这就像经理决定:"戴领带对生产力不利,所以我们都会在脖子上戴上遮蔽胶带.问题解决了."

  • +1仅用于短语"使用特殊值表示NULL(已经是表示NULL的特殊值)"... (10认同)

sta*_*ica 9

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

(顺便说一句,我不是特别喜欢与承包商合作,他们告诉你他们和其他"高级"DBA比你更了解和更好.)

 +=================================+
 |  FavoriteLetters                |
 +=================================+
 |  Person      |  FavoriteLetter  |
 +--------------+------------------+
 |  'Anna'      |  'A'             |
 |  'Bob'       |  'B'             |
 |  'Claire'    |  'C'             |
 |  'Zaphod'    |  'Z'             |
 +---------------------------------+
Run Code Online (Sandbox Code Playgroud)

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

可能他会在这张表中选择一个不同的"魔术值"来避免与真实数据发生冲突'Z'?这意味着你必须记住几个魔法值以及哪个使用哪个...这比只有一个魔法标记更好NULL,并且必须记住随之而来的三值逻辑规则(和陷阱)?NULL与承包商不同,至少是标准化的'Z'.

我并不特别喜欢NULL下去,但与实际值盲目将其代(或者更糟,有几个实际值)无处不在,几乎比肯定更差NULL.

让我在这里重复我的上述评论以获得更好的可见性:如果你想阅读那些反对的人认真的事情NULL,我会推荐一篇简短的文章"如何处理缺少的信息而不使用NULL"(链接到PDF来自第三宣言主页).


nvo*_*gel 5

原则上,正确的数据库设计不需要空值。事实上,有很多数据库在设计时没有使用 null,并且有很多非常优秀的数据库设计者和整个开发团队在设计数据库时没有使用 null。一般来说,在向数据库添加空值时保持谨慎是一件好事,因为它们稍后不可避免地会导致不正确或不明确的结果。

我没有听说过使用 Z 被称为“标准实践”作为占位符值而不是空值,但我希望您的承包商指的是一般的哨兵值的概念,有时在数据库设计中使用它。然而,在不使用“虚拟”数据的情况下避免空值的更常见和灵活的方法是简单地设计它们。分解表,以便每种类型的事实都记录在没有“额外”、未指定属性的表中。