我知道这个话题有点争议,互联网上有很多各种各样的文章/观点。不幸的是,他们中的大多数人都假设该人不知道NULL和空字符串之间的区别是什么。因此,他们通过联接/聚合讲述令人惊讶的结果的故事,并且通常会做一些更高级的SQL课程。通过这样做,他们绝对错过了整点,因此对我毫无用处。因此,希望这个问题和所有答案将使话题向前发展。

我假设我有一个包含个人信息(姓名,出生等)的表,其中一列是varchar类型的电子邮件地址。我们假设出于某些原因,某些人可能不想提供电子邮件地址。将此类数据(不带电子邮件)插入表时,有两个可用的选择:将单元格设置为NULL或将其设置为空字符串('')。让我们假设我知道选择一个解决方案而不是另一个解决方案的所有技术含义,并且可以为任何一种情况创建正确的SQL查询。问题是,即使两个值在技术层面上都不同,但在逻辑层面上却完全相同。看完NULL和”之后,我得出一个结论:我不知道那个人的电子邮件地址。同样,无论我多么努力,我都无法使用NULL或空字符串发送电子邮件,因此显然大多数SMTP服务器都同意我的逻辑。因此,我倾向于在不知道值的情况下使用NULL,并认为空字符串是一件坏事。

与同事进行了激烈的讨论后,我想到了两个问题:


我是否假设使用空字符串作为未知值会导致数据库对事实“撒谎”?更准确地说:使用SQL关于什么是价值和什么不是价值的想法,我可能得出结论:我们拥有电子邮件地址,只是发现它不为空。但是后来,当尝试发送电子邮件时,我会得出一个矛盾的结论:不,我们没有电子邮件地址,@!#$数据库一定是在说谎!
有没有逻辑场景中,空字符串”可以很好地承载重要信息(除了值和无值),而通过其他任何方式(如附加列)存储起来都将很麻烦/效率低下。我看过很多文章声称有时将空字符串与实数值和NULL一起使用是很好的,但是到目前为止,还没有看到一种符合逻辑的方案(就SQL / DB设计而言)。

PS有些人会试图回答,这只是个人品味的问题。我不同意对我来说,这是一个具有重大后果的设计决策。因此,我希望看到一些出于逻辑和/或技术原因而对此选择表示支持的答案。

评论

您是否知道在Oracle中,空字符串为NULL?

@ammoQ:Oracle对零长度字符串的处理是非标准的。此外,“”即使在Oracle中也不同于NULL。例如,为CHAR(1)列分配值“”将导致“”(即空格),而不是NULL。此外,如果Jacek使用的是Oracle,那么这个问题甚至可能不会出现:-)

Dean:您对char(1)示例是正确的,但这又是另一个WTF,因为在PL / SQL中,“ IS NULL的计算结果为true。

“我是否认为使用空字符串作为未知值会导致数据库对事实“撒谎”,对吗?”如果您的企业用户不在乎未知与空虚,那么说谎甚至没有关系吗?

如果必须使用字符串...请确保其为空。为了所有开发人员的利益,请勿让带有空格的字符串代表您的未知值。我求求你了。

#1 楼

我会说NULL是“没有电子邮件地址”的正确选择。有许多“无效”电子邮件地址,而“”(空字符串)只是其中之一。例如,“ foo”不是有效的电子邮件地址,“ a @ b @ c”无效,依此类推。因此,仅因为“”不是有效的电子邮件地址就没有理由将其用作“无电子邮件地址”值。

我认为您正确地说“”不是正确的方法说“我对此栏没有值”。 “”是一个值。

其中“”可能是有效值的示例,与NULL分开的可能是一个人的中间名。并非每个人都有中间名,因此您需要区分“无中间名”(“-空字符串”)和“我不知道此人是否有中间名”(NULL)。可能还有许多其他示例,其中空字符串仍然是列的有效值。

评论


完全同意。 NULL是有原因的。在您的电子邮件地址为[NOT]的情况下选择COUNT(*)是NULL,而不是比较慢的字符串比较(即使对于我想是空字符串,但我不确定这一点:)。

–LudoMC
2010-12-30 14:03

我认为NULL并不意味着没有电子邮件地址,我认为这意味着该电子邮件地址目前未知,不存在或者由于其他原因无法填写。幸运的是,在任何情况下都不会希望将确实没有或不打算拥有任何电子邮件地址的人的信息保留在数据库中,否则可能需要一个单独的布尔字段。

– Alexey
2012年8月8日在9:28

@Alexey-NULL表示没有值。正如其他人指出的那样,空字符串是一个值。

–猎犬
2012年8月9日在11:43

@Ramhound,我同意空字符串是一个值,而NULL隐约意味着“没有值”。我只是解释了我对“无价值”的解释。我认为,这与“该人尚未打开任何电子邮件帐户”不同。而是“没有为该人记录电子邮件地址”。

– Alexey
2012年8月9日19:08



@Ramhound NULL表示没有值。没有中间名的人在那里没有价值。因此,在中间的初始列中也应使用NULL ...与该答案中提出的论点完全相反。

–伊兹卡塔
2012年8月13日22:00

#2 楼

在同意上述意见的同时,我将此参数作为主要动机:


对于查看数据库的任何程序员来说,显而易见的是,标记为NULL的字段是Optional字段。 (即记录不需要该列的数据)。
如果将字段标记为NOT NULL,则任何程序员都应直观地认为它是Required字段。
在允许为null的字段中,程序员应希望看到空值而不是空字符串。

为了进行自我记录的直观编码,请使用NULL而不是空字符串。

评论


+1这是针对开发人员反对空字符串的“最少惊讶”参数。以后再也没有开发人员会期望使用空字符串来表示“没有电子邮件地址”。

–托马斯
2012年8月8日15:51

最后,在我检查的页面/答案中确实有一定意义的答案。我不是说英语的母语人士,也不住在讲英语的国家/地区。因此,提出的大多数区分空字符串和NULL的参数对我来说(至少到目前为止)毫无意义。

–akinuri
20 Mar 7 '20 at 10:24

#3 楼

在您的示例中,如果它是直接来自Web字段的值-我将使用空字符串。如果用户可以选择指定自己不想提供电子邮件,或者可以删除电子邮件-则为NULL。

这里是您可以考虑以下几点的链接:https://stackoverflow.com/ Questions / 405909 /与用户输入交易时空值vs / empty / 405945#405945

---已编辑(回复Thomas的评论)---

没有没有使用数据库的应用程序,它们就无法生存。如果应用程序不能正确使用NULL或'',则没有任何意义。

考虑一个示例,其中用户填写LONG表单并按Enter,它将向服务器发送持久请求。他可能正在输入电子邮件。很可能您想将他的所有内容存储在电子邮件字段中,以便稍后他可以完成它。如果他只输入一个字符怎么办?如果他输入一个字符然后将其删除怎么办?当不需要电子邮件时,有时用户希望将其删除:这是清除字段的最简单方法。同样,如果不需要电子邮件,则值得在发送之前对其进行验证。

另一个示例:用户以spamto @ [bigcompany] .com提供电子邮件-在这种情况下,即使存在并且有效(甚至可能存在),也无需发送电子邮件。发送这样的邮件可能很便宜,但是如果有1万名用户每天使用这种电子邮件订阅,则这种验证可以节省大量时间。

评论


-1。数据库是否在驱动网站无关紧要。设计数据库与网页设计的世界不同。数据库的设计应独立于用于写入数据库的接口来捕获有关业务领域的事实。按照您的逻辑,如果同时第一个应用程序是可执行文件,则应使用null吗?如果第一个应用程序是Web应用程序,而下一个应用程序是移动应用程序,会发生什么?设计数据库以使用规范化规则捕获事实,并设计网站对其进行写入。

–托马斯
2012年8月8日在16:11

我很高兴您学习了如何在该站点上编写和评论:)我仍然相信DB应该支持使用它的应用程序。检查我编辑的答案。

–康斯坦丁·彼得鲁赫诺夫(Konstantin Petrukhnov)
2012年8月9日在7:34

没有使用数据库的应用程序,数据库就无法生存。以我的经验,这根本不是真的,也是短视的。数据库几乎总是在为其设计应用程序之外使用。通常,数据库的生存期比为其构建应用程序的生存期更长。应该设计数据库来收集有关业务的事实,并且应该构建UI来读写数据库,而不是相反。关系设计是与应用程序设计完全不同的思维方式。

–托马斯
2012年8月9日15:39

数据库并非仅由原始应用程序使用的示例:报告,与其他系统的集成。

–托马斯
2012年8月10日15:08

正如Thomas所指出的,DB可以并且经常被多个应用程序使用,这增加了保持DB数据整洁的思想的重要性。如果您不希望/无法在应用程序中处理NULL,则可以在数据访问层将它们替换为“魔术值”(很好的描述Thomas)。这样,将来任何想要访问数据库的应用程序都无需了解/符合原始应用程序的魔术值。

– Bendemes
2012年8月29日在12:02

#4 楼

使用Null。

没有必要存储值”,只需将表中的字段设置为可空即可。它也使查询更加明显。

如果要查找具有电子邮件地址的用户,哪个SQL查询更明显和可读?




我会说2是。尽管在存储错误数据的情况下3更可靠。

对于表格上的电子邮件地址(可选),它也应反映在表格中。在SQL中,它是一个可为空的字段,这意味着它未知。这就像存储字符串值'NULL'或'BLANK',并让开发人员假定其为null或空字符串一样。对我来说,这是不好的设计。

为什么要存储它呢?

只使用NULL,就会使每个人都更加高兴。

更多信息:

SQL使用三值逻辑系统:True,False和Unknown。

#5 楼

我认为Dean Hardings的回答很好地涵盖了这一点。话虽如此,我想提到在数据库级别谈论NULL与空字符串时,您应该考虑一下其他数据类型。如果没有提供日期,您会存储最小日期吗?或-1(如果没有提供int)?当没有值时存储值意味着必须跟踪整个非值范围。每种数据类型至少一个(可能会在实际值为-1的情况下获得更多,因此您需要一些替代方法,等等)。如果您需要/想要在应用程序级别上做一些“前卫的事情”,那是一回事,但是他们不需要污染您的数据。

评论


+1-这就是我所说的“神奇价值解决方案”。我们必须为每种数据类型提出一个魔术值,以表示缺少值。另外,在某些列中,公共魔术值是或变为合法值,因此需要新的魔术值。

–托马斯
2012年8月8日16:06

#6 楼

不幸的是,Oracle将长度为零的VARCHAR字符串表示形式与NULL表示形式相混淆。它们在内部均由值为零的单个字节表示。这使讨论变得更加困难。

围绕NULL的许多困惑都围绕着三值逻辑。考虑下面的伪代码:

if ZIPCODE = NULL
    print "ZIPCODE is NULL"
else if ZIPCODE <> NULL
    print "ZIPCODE is not NULL"
else print "Something unknown has happened"


您不会期望第三条消息,但这就是在三值逻辑下得到的。三种有价值的逻辑会导致人们发现许多错误。通常,这些推论不是NULL的作者打算进行的。

已经说过,在很多情况下NULL可以很好地处理缺少数据的情况,并能准确地产生您想要的结果。一个示例是可选关系中的外键。如果使用NULL指示给定行中没有关系,则该行将按照您的期望从内部联接中退出。存储的数据(第六种标准形式),如果执行任何外部联接,您仍将不得不应对NULLS。

#7 楼

对于特定的技术问题,问题不是null vs空字符串,这是验证失败。空字符串不是有效的电子邮件地址!

对于哲学问题,答案相似:验证您的输入。如果空字符串是所讨论字段的有效值,则应对其进行编码。如果不是,请使用null。

空字符串将是回答以下问题的有效输入:哑剧对长颈鹿说了什么?

评论


即使具有世界上最好的意图,验证也不能解决这个问题-他可能仍然必须使用一种处理行的方法,其中必须为所有列提供某种值。在那种情况下,问题将依然存在-没有价值时使用什么价值?答案当然是:表明没有价值的价值。在数据库中,通常为NULL。

– jmoreno
13年3月15日在5:24

#8 楼

我可能会想到使用NULL和空字符串的原因:您有有效的电子邮件地址:一个):me@example.com

您知道这个人没有电子邮件地址:NULL


但是我不建议这样做,请使用单独的字段询问是否知道不存在。

#9 楼

据我了解,问题是应该选择NULL和空字符串的解释。这取决于particualar字段可以处于多少个状态。

解释取决于如何访问数据库。如果代码中有一层可以完全抽象出数据库,那么选择可行的任何策略(包括两个库)都是完全可以接受的。 (不过,清楚地记录该政策很重要)。但是,如果要在多个地方访问数据库,则应该使用非常简单的方案,因为代码将更难以维护,并且在这种情况下可能是错误的。

#10 楼

好吧,基本上在逻辑层面上,“无效”值和“无用户输入”之间没有区别,大多数情况下它们都是“特殊情况”。错误的情况。

具有null会占用附加空间:ceil(columns_with_null / 8)以字节为单位/每行。应该是默认值。为什么需要2个“错误”状态?如果NULL占用额外的空间并且与空字符串完全相同,为什么还要使用NULL?当您有两个含义(可能意味着)完全相同时,这只会引入混乱和冗余,很容易忘记您应该使用NULL而不是空字符串(例如,如果用户省略了某些字段)。 >
您的数据可能变得一团糟。在一个完美的世界中,您会说“数据将始终是正确的,我会记住的” ...但是,当人们必须在团队中工作并且并非每个人都在您的水平上时,看到WHERE的情况并不少见(aa。 xx <>''AND bb.zz不为空)

因此,我不必每隔一天纠正我的团队成员,而是执行简单的规则。没有null值,从不!

计算NON-NULL值更快……简单的问题是,您需要做什么呢?

评论


我隐约记得在某处读过,使用NULL实际上是数据库的一项成本(在计算和存储方面)。提出这个公式的好处很重要。

–雅克·普鲁西亚(Jacek Prucia)
2011年1月4日在8:44

不要忘记,VARCHAR列将至少占用1个字节来存储字符串的长度,即使它为零。

– dan04
2011年2月21日,0:01

空单元格和null都是标记某些错误的方式。不对。空值是一种指示缺少值的方法。我敢打赌大多数RDBMS在每一行上使用一个位数组来指示哪些列为空。因此,额外的空间是如此之小以至于无关紧要。担心额外的处理是过早的优化,与为其他开发人员“发现”您故意使用空字符串而创建的减速带相比,它毫无用处。

–托马斯
2012年8月8日16:00

没有空值。这是鸵鸟的方法。 “我们将全神贯注于沙子,并声明不存在缺失的价值”。这通常会导致产生“魔术值解决方案”,在该解决方案中,您必须为每种数据类型提供一个魔术值来表示缺少值。

–托马斯
2012年8月8日在16:04

#11 楼

我倾向于不是从数据库的角度来看它,而是从程序的角度来看它。我知道这个问题是针对SQL单击的,但实际上,有多少用户不再直接访问数据?

在程序中,我不喜欢null / nothing。有一些例外,但仅此而已。这些异常实际上只是不好的实现。

因此,如果用户未输入电子邮件,则应该有一些东西可以确定这是否有效。如果可以使用空白电子邮件,则显示空白字符串。如果用户未放入电子邮件中并且违反了规则,则该对象应指出这一点。

即使在DB设计中,为什么email字段也不能不允许空值且长度为零的字符串,而另一个字段则指示用户是否输入了内容? DBMS有那么多要求吗?在我看来,数据库既不应该处理业务逻辑也不应该处理显示逻辑。它不是为此而构建的,因此在处理它方面做得很差。

评论


为什么email字段不能不允许空值且字符串长度为零-简单地说:因为任何对数据库一无所知的开发人员都不会期望空字符串具有魔术的含义。您试图使自己的魔术值代表每个数据库中已经基本存在的值:一种表示不存在值的概念。为什么要重新发明轮子?而且,NULLS的想法离老派还很遥远。空是理解关系数据库设计的基石。

–托马斯
2012年8月8日15:55

大声笑。就像我从程序员的角度说过的那样,空值几乎总是使人痛苦不堪,并且对于Business LOGIC几乎不需要。作为开发人员,我个人并不关心关系设计。如果我做到了,我将是一名DB兄弟。如果我从数据库中得到一个空值,我几乎总是将其转换为有理数,例如一个空字符串,然后让我光荣的OOP设计做到这一点很神奇。该框架负责解决DBA对世界施加的那些愚蠢的无效行为。我知道DB帅哥必须处理它,我对您有帮助。但是,作为程序员,我不必这样做。我有更好的解决方案。

– ElGringoGrande
2012年8月10日,下午2:31

您“从不”必须处理空值。因此,您所描述的是鸵鸟解决方案与神奇价值解决方案的结合。 “我将忽略缺少值的事实,并将所有空整数都转换为-1”。直到有一天-1是真实值。应当指出,MS向.NET添加泛型的原因之一是为了解决数据库和应用程序代码之间的巨大阻抗不匹配问题,并且该问题主要围绕在中间层代码中表示空值的问题。这些“傻空值”也存在于业务逻辑中。

–托马斯
2012年8月10日15:14

db中不存在某些整数(或为null)的事实并不意味着我必须用-1来表示它或evan nullable(int)。如果您认为这是处理null的唯一方法,那么您就不会很好地理解编程。请记住,null就是一无所有。如您所说,null代表某种数据结构中缺少值的占位符。这意味着什么。业务逻辑很少(这与从不一样)很少需要此概念,因为它与行为有关,而不是数据。而且,当它为null时,很少是代表这一点的最佳方法。

– ElGringoGrande
2012年8月11日18:34



即使是业务逻辑,也必须考虑(含义代表)缺失的值,根据我的经验,在过去20年来我所见过或构建的几乎每个系统中,这都是正确的。该数据库正在对要捕获和存储的业务事实进行建模。如果业务逻辑希望能够与数据库交互,则它必须知道如何处理空值。无论是自定义结构,魔术值还是泛型都无关紧要。业务逻辑需要具有处理从数据库接收到的缺失值的能力,以及将值标记为对数据库缺失的能力。

–托马斯
2012年8月12日15:37

#12 楼

我认为这没什么大不了,但是当存在NULL时,我会更喜欢它。如果它表示NULL并且背景具有不同的颜色,则为缺少的值。

如果我看到一个空格,我总是想知道它是否真的是空的,或者是否有空白或一些不可见的字符。使用NULL可以保证一眼就能看到空。



我通常不区分应用程序中的值,因为这是意外的,而且很奇怪NULL和空字符串会意思不同。在大多数时候,我采取防御性方法,只与两个州打交道。但是对于我个人来说,在查看数据时更容易处理NULL。

评论


在前面的12个答案中,这似乎并没有提供任何实质性的解释。

– gna
16年8月11日在15:05

@gnat:我不同意,答案中没有人提到人类查看数据的方面。只有一个NULL值,但是可以有很多看起来像空字符串的值(不仅是空格,而且还有很多奇怪的Unicode字符)。我看不到任何其他提及此问题的答案。

–汤姆(TomPažourek)
16年8月11日在15:20

据我所知,这是在5年前发布的第二个最佳答案中列出的:“对于任何看数据库的程序员来说都是显而易见的……”等等

– gna
16年8月11日在15:25



@gnat:我明白你的意思,尽管我认为作者的意思不同。我相信他更多地是关于NULL表示可选字段,但是空字符串也可以用于必填字段,因此NULL对于缺少值更合乎逻辑。我同意他的观点。但是我的答案指出了一个事实,即空字符串并不比NULL值明确,因为许多事情乍一看可能看起来像空字符串,而实际上并不是空字符串。

–汤姆(TomPažourek)
16年8月11日在15:36