为什么负 id 或零被认为是一种不好的做法?

Why is negative id or zero considered a bad practice?

提问人:falsarella 提问时间:1/19/2012 最后编辑:falsarella 更新时间:2/5/2018 访问量:24150

问:

为什么在数据库表中插入主键时,负 id 或零被认为是一种不好的做法?

我认为它在某些情况下可能有用,但人们说不推荐它,尽管他们从未说过/知道为什么。

所以,我想知道根据定义,是否存在一些限制,或者它是否应该有任何问题,或者它是否只是一个约定,如果真的有一些限制,为什么这个功能没有被阻止?

数据库设计 主键 标识符 最小惊奇

评论

0赞 Yuck 1/19/2012
你有什么可以记录这种“坏做法”吗?我想负数读起来更不愉快,打字也更难。我真的看不出有任何技术理由来避免它们。事实上,这是扩展有符号数据类型范围的好方法。
1赞 Niklas 1/19/2012
另一方面,这在客户端创建记录时很有用,以后需要插入到服务器上: msdn.microsoft.com/en-us/library/ms971502.aspx
0赞 falsarella 1/19/2012
我想负数被“认为”是一种“不好的做法”,是“避免”的“丑陋”的东西,这是很流行的。不是吗?但我真的不明白为什么......那么,@Yuck,你认为这是因为可读性吗?
2赞 RHamblin 1/19/2012
dba stackexchange 上的一些讨论可能会提供一些观点。dba.stackexchange.com/questions/2895/......但是,我真的不确定为什么不使用它们的充分理由。
0赞 falsarella 1/23/2012
找到了一些关于 .NET 的信息(这不是我使用的,但其他人可能会使用该信息): stackoverflow.com/q/2473215/1064325

答:

37赞 Mike Sherrill 'Cat Recall' 1/22/2012 #1

需要明确的是,这个问题和答案是关于对代理键使用负数,而不是对自然键使用负数。

据我所知,有三个原因认为这是一种不好的做法。

  1. 它违反了最小意外原则
  2. 有些人认为所有身份证号码都是非负数。
  3. 有些人使用负数来表示错误。

第一个有一定的道理。您永远不会在 SO 上看到使用负 ID 号的 SQL 示例或答案。(从今天开始,我将改变这一点。

第二和第三种是第一种的推论,因为程序员经常假设没有意外的行为。(这让我想起了发现 VBA 会让我将两个日期相乘,返回一个数字,我猜这个数字会用方形日期表示。

对于第 2 点,应用程序程序员可能会通过不为登录 UI 代码留出空间而引入细微的错误,这可能会使 -123456 看起来像123456。

第三个与编写返回 ID 号的代码有关。返回单个 ID 号的代码可能会返回 -1 作为错误代码。但在大多数情况下,-1 是有效的 ID 号。(大多数数据库不会将 ID 号限制在非负整数范围内。

评论

0赞 falsarella 1/26/2012
你认为这些原因与零相同,还是有什么不同?
2赞 Mike Sherrill 'Cat Recall' 1/26/2012
我认为零也是如此。有些地方使用 0 作为 NULL 的一种非 null 替换。
1赞 falsarella 1/27/2012
那就没有限制了,谢谢!问题将出在实现代码上。但。。。对管理员用户使用 -1 或一些类似的常量怎么样?你如何处理?
0赞 Mike Sherrill 'Cat Recall' 1/27/2012
在这种情况下,身份证号码应该识别一个人,仅此而已。如果您还想知道某人是否是管理员,请将其 ID 号存储在“admins”表中。
1赞 Mike Sherrill 'Cat Recall' 2/5/2018
@wdetac:OP的问题和我的回答都是关于替代密钥的。我将编辑我的答案以使其更清晰。根据定义,代理键毫无意义。但是,使用负数来表示状态代码表中的错误是完全不同的用例。在这种情况下,负数是自然键,而不是代理键;他们一点也不奇怪。
12赞 avnr 12/30/2015 #2

@Mike Sherrill 的答案“猫召回”恕我直言,这是不正确的。

负数:不对 ID 使用负数的原因是负数不可移植。十进制值的二进制表示取决于底层数字体系结构,这会影响负十进制值以非负流格式(例如十六进制、base36 等)呈现的方式。同样,人们不使用浮点值作为标识符,即使在单个体系结构的约束下,理论上也是可能的。

零:零可以作为 ID。但是不建议这样做,因为它通常表示空字段/NULL 值。

评论

0赞 falsarella 12/30/2015
好点子。+1.你有关于它的任何消息来源吗?从来没有想过表示架构,但无论如何,对于其他字段类型来说,它仍然存在可移植性问题......因此,最小意外原则似乎仍然是一个更相关的原因。
2赞 avnr 12/30/2015
从形式上讲,标识符是一个标记(en.wikipedia.org/wiki/Identifier 中有一个很好的概述),因此只有当您将负数视为字符序列时,才能将其视为标记,这有点违背了其“负”的性质。因此,在您的问题上下文中,如果 ID 是数字而不是字符串,则此数字不应用作负数的 ID。这不仅仅是一个建议,就像在“最小意外原则”的情况下一样,恕我直言,使用负 ID 是错误的。也许使用浮点数作为 ID 的更极端的例子更直观。
2赞 falsarella 12/30/2015
我认为有几种方法可以备份和移植数据库。二进制备份/可移植性是一种选择,但我们并不局限于此。真正的错误是依靠物理架构来备份或移植某些内容。正如我所提到的,如果发生这种情况,对于任何其他不可移植的列来说,可移植性仍然是一个问题。因此,为 PK 解决它实际上并不能解决任何问题。你的陈述不仅适用于PK,它适用于任何数字列,所以如果允许否定,在任何地方使用它都是错误的,这真的是无稽之谈。
0赞 avnr 12/30/2015
备份和移植没有真正的问题,因为在这些情况下,编码得到了很好的控制。当您在接口中使用 ID 时,问题就开始了。这是一种非常常见的架构,例如,ID 在某些基数中具有固定的字符宽度,作为将值验证为 ID 的一种方式。但是,除非架构指定负数的编码,否则您不能对负数执行此操作:LSB 或。MSB,一个补码或两个补码等,这是不切实际的。这与数据字段不同,因为数据字段只是数字,而不是标记。
0赞 avnr 12/30/2015
也许这会更简单:假设我们有一个 ID 为“-10”的项目。如果将 ID 解释为由 hyphen-one-zero 的 ascii 表示形式组成的三个字节,则没问题,这是一个有效的 ID。但是,如果您希望将此 ID 视为数字(因为这一点是您问题的核心),那么它的标记化仅作为有符号小数是无歧义的。除非您指定特定的数字体系结构,否则您无法在任何其他常见表示形式中明确地对其进行标记,而不会丢失其数值的元。
-2赞 vrn53593 12/30/2015 #3

有超过 5100 万个网站在讨论这个问题。

我同意 Sherrill @Mike的观点,NULL/空字段或负 ID 在确定真实值时可能会造成严重问题,这很常见。它根本没有信息目的,只会导致不正确的答案和对数据库本身的不信任。

在列中允许零值,负值会给数据库带来全新的不确定性。SQL 程序员必须进行猜测,以计数数据库中 NULL 值的错误结果。