Null的姓氏如何在许多数据库中引起问题?


71

我读了一篇关于英国广播公司的文章。他们说的一个例子是,姓“ Null”的人在某些网站上输入详细信息时遇到问题。

没有给出关于他们面临的错误的解释。

但据我所知,字符串“ Null”和实际的Null值完全不同(从数据库的角度来看)。

为什么这会在数据库中引起问题?


2
这是关于假设一个小有名气的博客文章中,程序员做出名,由英国广播公司的文章中引述其中的人写的:kalzumeus.com/2010/06/17/...
约尔格W¯¯米塔格



4
我第一次在电视上看到这个家伙时,我以为是数据库错误。然后我发现实际上是他的名字。
Nate Eldredge

3
@JarrodRoberson考虑到“ Jennifer Null”面临的问题的描述以及OP发布的链接中的类似名称,您怎么说“整个前提都是错误的”?这是真正的最终用户面临的现实问题。
史蒂芬·本纳普

Answers:


102

它不会引起数据库问题。它会在不了解数据库的开发人员编写的应用程序中引起问题。问题的根源是许多与数据库相关的软件都将NULL记录显示为字符串NULL。然后,当应用程序依赖于NULL记录的字符串形式(可能还使用不区分大小写的比较操作)时,则此类应用程序会将任何"null"字符串视为NULL。因此,该应用程序将认为名称Null不存在。

解决方案是NOT NULL在数据库中声明非空列,并且不对数据库记录应用字符串操作。大多数语言都有出色的数据库API,这些API不需要字符串级的接口。应该始终首选它们,因为它们会使其他错误(例如SQL注入)的可能性降低。


30
但是,在这种情况下,如果您阅读有问题的文章,则姓氏字段NOT NULL将对其他人造成一系列问题。“有些人只有一个名字,没有一个姓氏和姓氏。”
MikeTheLiar '16

41
@Darkhogg在这个问题上有很多人不同意我的看法,但是我认为名字就像电子邮件地址一样-不用费心验证它们,给用户一个文本框,然后让他们放任何想要的东西。这些信息是,如果我真的需要它,我会以一定正确的方式从您那里获取它。
MikeTheLiar '16

8
@mikeTheLiar我不知道这个名字,但是由于对数据创建了过于严格的规则而导致了一整类错误。通常,您会在应用程序和数据库中看到定义为数字的邮政编码和电话号码。它们并不是真正的数字,因为对它们进行数学运算没有任何意义。因此,当有人尝试输入加拿大地址时,他们就被卡住了。
JimmyJames

19
@JimmyJames是的,邮政编码存储为数字,突然间住在这里的任何人都有以8为底的邮政编码。“如果您不使用它做数学运算,那是一个字符串,句号”。
MikeTheLiar '16

8
@mikeTheLiar。将名称视为单个字符串的问题(通常,我同意,这是一个问题)是当需要按姓氏按字母顺序排序时。
TRiG

13

为了回答您的特定问题,Web表单和数据库之间的事件链有许多步骤。如果姓氏Null被错误地解释为NULL值,则系统可能会拒绝完全正确的名称为无效名称。如amon所述,这可以在数据库层发生。顺便说一句,如果这是特定问题,那么该数据库也可能会受到Bobby Tables攻击的SQL注入攻击。链中可能引起问题的另一个步骤是序列化过程

总体而言,这篇文章是关于一个更大的问题的。世界是一个大杂乱的地方,并不总是符合我们的假设。当您尝试国际化您的应用程序时,这一点尤其明显。最终,我们需要确保我们的应用程序正确处理和编码我们的数据。取决于我们的业务是由我们决定为支持日益复杂的边缘情况分配多少资源。尽管我完全支持包容性,但我会理解企业是否认为“正式被称为Prince的艺术家”需要使用Unicode字符来表示他在我们数据库中的名字。


很难想象这是由可能导致SQL注入的某种不安全的字符串插值引起的。如果您忘记在SQL查询中引用用户输入(例如,INSERT INTO users (first, last) VALUES($first, $last)对进行引用INSERT INTO users (first, last) VALUES(Jennifer, Null)),则其名称不是有效的SQL关键字或列名称的每个人都将抛出错误,也不会插入其记录。原因必须更加复杂。
Andrew Medico

是的,@ AndrewMedico是您的例子,但是有很多方法可以解决错误。永远不要低估<strike> stupidity <\ strike>无知的力量。底线是我们不知道实际的问题是什么,因为我们无法查看有问题的代码
Erik

7

好吧,在将其输入数据库之前,它是一个DOM元素,然后是一个传递,验证和操作的javascript变量,一个JSON值,然后是您使用的任何后端JSON库中的一个变量,然后是一个传递的变量,在您的后端编程语言中进行验证和操作,然后是某种DAO的元素,然后是SQL字符串的一部分。然后,要取回价值,可以反向进行。程序员在很多地方都容易犯错误,通常很多地方都没有静态类型的好处。


2

最有可能是编程问题。如果您在此处查看有关如何传递NULL的答案,而如果您是“ Nr。Null”,则很容易导致某些不良行为。

https://stackoverflow.com/questions/4620391/mysql-and-php-insert-null-rather-than-empty-string

您可以看到,如果某些数据元素作为NULL传递,则数据将被插入为数据库中的数据库null。

“ NULL”!=数据库为空

一些用例和相关行为...

假设姓氏在数据库中被标记为非null,现在插入数据时它将被解释为NULL并导致插入失败。

另一种情况是,假设姓氏在数据库中为空。插入了NULL先生并将其转换为与“ NULL”不同的DBNull.Value。插入之后,我们找不到Null先生,因为他的姓氏不是“ NULL”,而实际上是数据库的null值。

因此,那将是2种问题。正如@Amon指出的那样,数据库本身没有null的问题,尽管应该理解每个RDMS实例中null的处理方式,因为不同供应商之间会有差异。


“您可以看到,如果某些数据元素作为NULL传递,则数据将被插入为数据库中的数据库null。” -链接的SO问题/接受的答案似乎没有显示此内容?
MrWhite 2016年

2

我将问题归结为草率的编程和某些SQL实现的不良设计。名称为“ Null”时,应始终用引号引起来并进行解释。数据库值null始终应不带引号;但是在编写临时代码时,很容易陷入“任何事情都会做”的范式,并接受被认为是无引号形式的字符串的事物。

其他类型的数据使情况更加复杂。例如,因为解释是明确的,所以可以并且可以以任何一种形式接受数字。


您肯定是指使用 SQL 的应用程序实现不佳吗?RDBMS本身的任何认真实现都不会受到此攻击(就像没有认真的应用一样!)
underscore_d

0

从根本上讲,一个问题是术语“空”被应用于两个不同的数据库概念,有时使用上下文来区分它们:

  1. 没有已知的价值
  2. 已知没有任何价值

尽管上下文有时足以区分这些概念,但有时确实没有。例如,如果某人使用一条记录来保存搜索查询,则说“我想要一个名字为[whatever]且没有姓氏的人”与“我想要一个名字为[随便],但姓氏未知。” 许多数据库引擎对一种含义或另一种含义都有偏见,但是它们并不完全相同。如果在不同的引擎上运行,则期望数据库引擎以一种方式工作的代码可能会发生故障。


如果已知一个字符串没有值,则该值应为空字符串,而不是空字符串。
拜伦·琼斯

0

现有的大多数答案都集中在应用程序的非SQL部分,但SQL也可能存在问题:

如果指示过滤掉用户姓氏不可用的记录,则不太了解SQL的人可能会编写过滤器WHERE u.lastname != 'NULL'。由于SQL的工作方式,这似乎将检查是否u.lastname IS NOT NULLNULL筛选出所有记录。NULL保留所有非记录。

当然,对于的记录u.lastname == 'NULL',但在测试过程中可能没有任何此类记录。

如果SQL是由某种框架生成的,则这种可能性就更大了,在该框架中,该框架没有提供一种易于访问的方法来检查NULL参数是否不存在,并且有人注意到“嘿,如果我传入字符串NULL,正是我想要的!”

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.