SQL:使用NULL值与默认值

问题描述 投票:39回答:13

在SQL中使用NULL值而不是默认值的优缺点是什么?

PS。这里已经提出了许多类似的问题,但没有人回答我的问题。

sql database ms-access database-design
13个回答
38
投票

数据库中的NULL值是占用一个存储字节的系统值,表示不存在值而不是空格或零或任何其他默认值。包含NULL值的数据库中的字段表示此单元格的内容在查看时未知。允许NULL值的列也允许插入行,该列中根本没有值。使用NULL值而不是默认值有几个优点和缺点:

优点

NULL值没有数据类型,因此可以插入任何数据结构和任何数据库列。另一方面,默认值需要指定其数据类型,并且一列中的默认值在另一列中看起来可能相同,但它可能是不同的类型。

NULL通常用于模式中,其中值是可选的。这是一种省略未知字段数据输入的便捷方法,而无需实现其他规则,例如在整数字段中存储负值以表示省略的数据。

由于NULL值仅占用1位内存空间,因此在优化数据库时它们可能很有用。使用这些值比默认值更有效,例如字符的8位和整数的16位。

虽然您的系统要求可能会随着时间的推移而发生变化,并且默认值类型也随之改变,但NULL值始终为NULL,因此无需更新数据类型。

在表格模式中分配Not Null也可以帮助进行表格验证,因为具有Not Null条件的列将需要插入值。默认值没有这些功能。

缺点

NULL值很容易与空字符串混淆,空字符串在选中时会向用户返回空值。从这个意义上讲,默认值不那么容易混淆,并且是更安全的选项,除非将默认值设置为空字符串。

如果数据库中允许使用NULL值,它们可能会使设计人员有一些额外的时间和工作,因为它们会使数据库逻辑变得更复杂,尤其是当存在大量与空值的比较时。

资料来源:Pro and cons


1
投票

正如一位响应者已经说过的那样,NULL不是一个值。

任何说“NULL值”的人宣称的任何东西都是非常有用的,好像它是一个值。

NULL不等于它自己。如果x和y都为NULL,则x = y产生false。如果x和y都是默认值,则x = y得到true。

这种看似非常简单的差异几乎无穷无尽。而这些后果中的大多数都是诱人的陷阱,让你感到非常糟糕。


0
投票

Allen Browne关于Nulls的两篇非常好的面向Access的文章:

在VBA代码中使用Nulls的方面:

这些文章是面向访问的,但对于使用任何数据库的人来说可能是有价值的,特别是相对新手因为写作的会话风格。


0
投票

Nulls永远不会在DB2 for OS / 390和z / OS中节省存储空间。每个可空列都需要一个额外的存储空间用于空指示符。因此,可以为空的CHAR(10)列每行需要11个字节的存储空间 - 数据为10个,空指示符为1个字节。无论列是否设置为null,都是这种情况。

DB2 for Linux,Unix和Windows有一个压缩选项,允许将列设置为null以节省空间。使用此选项会导致DB2从列中设置为null的行中消除未使用的空间。但是,此选项在大型机上不可用。

REF:http://www.craigsmullins.com/bp7.htm

因此,DB2 Z / OS的最佳建模实践是使用“NOT NULL WITH DEFAULT”作为所有列的标准。我知道的一些主要商店也是如此。通过消除对NULL INDICATOR使用额外字节的需要,使得程序员的生活更加轻松,无需处理Null指示符并实际节省存储空间。


0
投票

我非常感谢所有这些讨论。我正在建立一个数据仓库,而且我正在严格地使用Kimball模型。然而,有一个非常有声音的用户讨厌代理键并且想要在整个地方使用NULL。我告诉他,对于维度的属性以及计算中使用的任何日期或数字,都可以使用NULLable列,因为默认值意味着数据不正确。我同意在某些列中允许NULL的优点但是如果对于维度的每个外键都有代理键,它会使Cubing更好更可靠,即使该代理对于虚拟记录是-1或0 。 SQL喜欢用于连接的整数,如果缺少维度值并且虚拟提供为代理键,那么您将使用一个维度获得与在另一个维度上立方体相同数量的记录。但是,必须正确地进行计算,并且必须适应那些中的NULL值。例如,生日应为NULL,以便不计算年龄。我相信良好的数据治理并且与用户一起做出这些决定迫使他们以比以往更多的方式思考他们的数据。


17
投票

我不知道为什么你甚至试图将这些与案例进行比较。 null表示某些列为空/没有值,而当我们不在查询中直接设置时,默认值会为列提供一些值。

也许一些例子将是更好的解释。假设我们有member表。每个成员都有一个ID和用户名。可选他可能有一个电子邮件地址(但他没有)。此外,每个成员都有一个postCount列(每次用户编写帖子时都会增加)。因此,电子邮件列可以具有null值(因为电子邮件是可选的),而postCount列是NOT NULL但具有默认值0(因为当我们创建新成员时他没有任何帖子)。


10
投票

空值不是......值!

Null意味着“没有价值”......除了数据库方面,非值变量或字段的一个重要维度是在比较变量时不可能使用'='(或'>','<')。

写一些像(VB):

if myFirstValue = mySecondValue

如果一个或两个变量都是非值,则不会返回True或False。您将不得不使用“周转”,例如:

if (isnull(myFirstValue) and isNull(mySecondValue)) or myFirstValue = mySecondValue

在这种情况下使用的“通常”代码是

if Nz(myFirstValue) = Nz(mySecondValue, defaultValue)

不严格正确,因为非值变量将被视为与'defaultValue'值(通常为零长度字符串)“相等”。

尽管存在这种令人不快的行为,但永远不要永远不要将默认值打开到零长度字符串(或“0”)而没有有价值的理由,并且在代码中简化值比较并不是一个有价值的理由。


5
投票

NULL值表示该属性不适用或未知。有宗教战争争论他们是好事还是坏事但是我陷入“好事”阵营。

在许多情况下,它们通常需要区分已知值和未知值,并且对于那些没有合适默认值的属性,它们不需要哨兵值。

例如,虽然银行余额的默认值可能为零,但手机号码的默认值是多少。您可能需要区分“客户没有移动电话”和“客户的移动电话号码尚未知晓”,在这种情况下,空白列不会(并且有一个额外的列来决定该列是否为1或其他不是一个好主意)。

如果没有明确指定,默认值就是DBMS将放入列的内容。


4
投票

对我来说,它们有些正交。

默认值允许您优雅地发展数据库模式(想想添加列),而无需修改客户端代码。另外,他们节省了一些打字,但依靠默认值是IMO坏。

空缺就是:nulls。在处理Three-Valued Logic时缺少价值和巨大的PITA。


4
投票

这取决于具体情况,但最终还是很简单。哪一个更接近真相?

很多人处理数据就好像它只是数据一样,而事实并不重要。但是,每当您与数据中的利益相关者交谈时,您会发现事实总是很重要。有时更多,有时更少,但它总是很重要。

当您可以假定如果用户(或其他数据源)提供了值时,默认值很有用,该值将是默认值。如果这个假设确实带来了更多的危害,那么NULL就更好了,即使处理NULL是一个痛苦的SQL。

请注意,有三种不同的方法可以实现默认值。首先,在应用程序中,插入新数据之前。数据库永远不会看到用户提供的默认值或应用程序提供的默认值之间的差异!

其次,通过声明列的默认值,并在插入中保留数据缺失。

第三,每当检测到NULL时,通过在检索时替换默认值。只有少数DBMS产品允许在数据库中声明第三种模式。

在理想的世界中,数据永远不会丢失。如果您正在为现实世界开发,最终将丢失所需的数据。您的应用程序可以执行有意义的操作,也可以执行某些操作无关紧要的操作。


4
投票

与许多事情一样,每个事物都有好的和坏的。

关于默认值的好处:如果没有给出其他值,它们使您能够将列设置为已知值。例如,在创建BOOLEAN列时,我通常会为列提供一个默认值(TRUE或FALSE,任何适当的值)并使列NOT NULL。通过这种方式,我可以确信该列将具有一个值,并且它将被设置为合适的。

关于默认值的不好之处:并非所有内容都有默认值。

关于NULL的好处:并非所有东西都具有已知值。例如,当创建一个代表一个人的新行时,我可能没有所有列的值 - 让我们说我知道他们的名字而不是他们的出生日期。为出生日期设置默认值是不合适的 - 如果他们的生日实际上是7月22日,那么人们不喜欢在1月1日获得生日卡(如果这是默认值)。

关于NULL的坏事:NULL需要小心处理。在大多数基于关系模型构建的数据库中,通常实现的NULL是有毒的 - 计算中存在NULL会导致计算结果为NULL。比较中使用的NULL也会导致意外结果,因为与NULL的任何比较都会返回UNKNOWN(既不是TRUE也不是FALSE)。例如,请考虑以下PL / SQL脚本:

declare 
  nValue NUMBER;
begin
  IF nValue > 0 THEN
    dbms_output.put_line('nValue > 0');
  ELSE
    dbms_output.put_line('nValue <= 0');
  END IF;

  IF nValue <= 0 THEN
    dbms_output.put_line('nValue <= 0');
  ELSE
    dbms_output.put_line('nValue > 0');
  END IF;
end;

以上的输出是:

nValue <= 0
nValue > 0

这可能有点令人惊讶。您有一个NUMBER(nValue),它小于或等于零且大于零,至少根据此代码。发生这种情况的原因是nValue实际上是NULL,并且所有与NULL的比较都会导致UNKNOWN而不是TRUE或FALSE。这可能导致细微的错误,很难弄清楚。

分享和享受。


3
投票

在数据仓库中,您始终希望拥有默认值而不是NULL。

相反,你会有“未知”,“未准备好”,“缺失”等价值

这允许INNER JOIN在Fact和Dimension表上高效执行,因为“一切都有值”


3
投票

Nulls和默认值是用于不同目的的不同东西。如果你试图通过给所有东西一个默认值来避免使用nulls,那么这是一个糟糕的做法,我将解释。

Null意味着我们不知道它的价值是什么。例如,假设你有一个enddate字段。您不知道记录的过程何时结束,因此null是唯一合适的值;使用某个假日期的默认值将来会导致编程和处理nulls一样麻烦,并且更有可能在我的经验中创建一个返回错误结果的问题。

现在有时我们可能知道插入记录的人不应该是什么值。例如,如果你有一个date inserted字段,那么拥有当前日期的默认值并且不希望用户填写此字段是合适的。你可能实际上有更好的信息来表示这个字段。

有时,这是一个判断调用,取决于您必须应用的业务规则。假设你有一个speaker honoraria字段(这是一个发言者得到的金额)。 0的默认值可能很危险,因为它可能意味着扬声器被雇用,我们打算不付任何费用。也有可能偶尔会有发言者为某个特定项目捐出时间(或者是公司的员工,因而没有额外付费发言),其中零是正确值,所以你不能使用零作为确定您不知道该演讲者支付多少的价值。在这种情况下,Null是唯一合适的值,如果有人试图将发言者添加到会议中,代码应该触发问题。在不同的情况下,您可能已经知道任何发言者的最低支付额为3000,并且只有经过协商不同费率的发言人将在honoraria字段中输入数据。在这种情况下,最好放入3000的默认值。在另一种情况下,不同的客户端可能具有不同的最小值,因此应该以不同的方式处理默认值(通常通过查找表自动填充数据输入表单上该客户端的最小honoraria值。

因此,我认为最好的规则是将值保留为null,如果您在输入数据时真正无法知道该字段的值应该是什么。使用默认值只有它具有该特定情况的所有时间的意义,并使用其他技术填写值,如果它在不同情况下可能不同。

© www.soinside.com 2019 - 2024. All rights reserved.