关系数据库中的空值可以吗?

时间:2020-03-06 15:02:16  来源:igfitidea点击:

有一种流派认为在关系数据库中不应该允许空值。也就是说,表的属性(列)不应允许空值。来自软件开发背景,我真的不明白这一点。似乎如果null在属性的上下文内有效,则应允许该值。这在Java中非常普遍,在Java中,对象引用通常为null。没有丰富的数据库经验,我想知道我是否在这里缺少什么。

解决方案

空标记很好。的确如此。

使用null绝对没问题。

从数据库规范化的角度看,空值是负面的。这样的想法是,如果值不能为空,那么我们实际上应该将其拆分为另一个稀疏表,这样就不需要没有值的项目的行。

这是确保所有数据有效且有价值的一种努力。

但是,在某些情况下,使用null字段很有用,尤其是在出于性能原因而希望避免再进行联接的情况下(尽管数据库引擎安装正确,这不应该成为问题,除非在特殊的高性能情况下。)

-亚当

将NULL用于数据字段没有任何问题。将键设置为null时必须小心。主键绝不能为NULL。外键可以为空,但是我们必须小心不要创建孤立记录。

如果某些内容"不存在",则应使用NULL而不是空字符串或者其他类型的标志。

根据严格的关系代数,不需要零值。但是,对于任何实际项目,都需要它们。

首先,许多现实世界的数据是未知的或者不适用的,而null可以很好地实现该行为。其次,它们使观点和外部联接更加实用。

这取决于。

只要我们了解为什么要在数据库中允许使用NULL(需要在每个列中进行选择)以及如何解释,忽略或者以其他方式处理它们,它们就可以了。

例如,像" NUM_CHILDREN"这样的列,如果不知道答案该怎么办,该怎么办?在我看来,此列的设计没有其他最佳选择(即使我们有一个标志来确定NUM_CHILDREN列是否有效,我们仍然必须在该列中有一个值)。

另一方面,如果我们不允许NULL并在某些情况下(而不是标志)具有特殊的保留值,例如-1(对于真正未知的孩子数量),则必须以类似的方式解决这些问题惯例,文档等方面

因此,最终,这些问题必须通过约定,文档和一致性来解决。

正如上述答案中亚当·戴维斯(Adam Davis)所明显支持的那样,另一种选择是将列标准化为稀疏表(对于NUM_CHILDREN示例或者大多数数据具有已知值的任何示例,则不那么稀疏),虽然能够消除所有NULL,但在一般实践中是不可行的。

在许多情况下,属性是未知的,因此对于每一列连接到另一个表几乎没有意义,这可以在更简单的设计中允许使用NULL。连接的开销,主键的空间要求在现实世界中意义不大。

这使我想到了一种方法,即通过添加基数列可以消除重复的行,而这从理论上解决了没有唯一键的问题,实际上在大规模数据中有时是不可能的。纯粹主义者随后很快提出了替代PK的建议,但是从关系理论的角度来看,无意义的替代可以在关系(表)中形成元组(行)的一部分的想法令人大笑。

我们会发现,通过逐步的数据采集系统,我们无法避免在数据库中出现空值,因为提问/收集数据的顺序很少与逻辑数据模型匹配。

或者,我们可以默认值(需要代码来处理这些默认值)。我们可以假设所有字符串都是空的,例如在模型中为null。

或者,我们可以具有暂存数据库表以进行数据获取,该表将持续进行直到获取所有数据为止,然后再填充实际的数据库表。这是很多额外的工作。

我会说绝对应该使用Null。没有其他正确的方法来表示数据不足。例如,使用空字符串表示缺少的地址行是错误的,或者使用0表示缺少的年龄数据项将是错误的。因为空字符串和0都是数据。空是表示这种情况的最好方法。

反对null的一种说法是它们没有明确定义。如果字段为空,则可以解释为以下任何一种:

  • 值为" Nothing"或者" Empty set"
  • 没有任何值对该领域有意义。
  • 该值未知。
  • 该值尚未输入。
  • 该值是一个空字符串(对于不区分null和空字符串的数据库)。
  • 某些特定于应用程序的含义(例如,"如果该值为null,则使用默认值。")
  • 发生错误,导致该字段在实际上不应该具有空值。

一些模式设计人员要求所有值和数据类型都应具有定义明确的解释,因此,空值是不好的。

对于数据库,null表示"我对此没有值"。这意味着(有趣的是)一个允许为空的布尔列是完全可以接受的,并且出现在许多数据库模式中。相反,如果代码中有一个布尔值可以为'true','false'或者'undefined'的布尔值,则我们迟早可能会在thedailywtf上看到代码:)

所以是的,如果我们需要允许一个字段根本没有任何值的可能性,那么在该列上允许空值是完全可接受的。它比潜在的替代方案(空字符串,零等)要好得多

关于法式的最好了解是它们是指南,不应牢牢遵守指南。当学术界与现实世界发生冲突时,我们很少会发现许多幸存的学术界战士。

这个问题的答案是可以使用null。如果我们认为空值与实际值的比率过高,则只需评估情况并决定是要它们显示在表中还是将数据折叠到另一个相关的表中。

正如朋友喜欢说的:"不要让完美成为善良的敌人"。想伏尔泰也这样说。 8)

我个人认为,仅当我们将字段用作另一个表的外键时,才应使用空值,以表示该记录未链接到另一个表中的任何内容。除此之外,我发现在对应用程序逻辑进行编程时,null值实际上非常麻烦。因为在大多数编程语言中,对于许多数据类型,没有直接表示数据库空值的数据库,所以最终会创建大量应用程序代码来处理这些空值的含义。当数据库遇到空整数,并尝试向其添加值1(又名null + 1)时,数据库将返回null,因为这是定义逻辑的方式。但是,当编程语言尝试添加null和1时,通常会引发异常。因此,代码最终会检查值为null时的处理方式,这通常只等于将数字转换为0,将文本转换为空字符串,并将日期字段转换为某些空日期(1900/1/1?)。 。

这是一大堆蠕虫,因为NULL可能意味着很多事情:

  • 没有死亡日期,因为该人还活着。
  • 没有手机号码,因为我们不知道它是什么,甚至不知道它是否存在。
  • 没有社会保险号,因为知道该人没有一个。

其中一些可以通过规范化来避免,某些可以通过该列中的值(" N / A")来避免,其中一些可以通过使用单独的列来解释NULL的存在来缓解(" N / K"," N / A"等)。

这也是蠕虫病毒的罐头,因为找到它们所需的SQL语法与非空值的SQL语法不同,很难对它们进行联接,并且它们通常不包含在索引条目中。

由于前面的原因,我们将发现不可避免的情况。

由于后一个原因,我们仍应尽最大努力减少它们的数量。

无论如何,请始终使用NOT NULL约束来防止需要值的空值。

而不是写所有的NULL问题,以及三态与布尔逻辑等问题,我将提供以下精妙的建议:

  • 在我们发现自己添加了一个魔术值来表示丢失或者不完整的数据之前,请不要在列中使用NULL。
  • 由于我们是在问这个问题,因此在处理NULL时应格外小心。有很多不明显的陷阱。如有疑问,请不要使用NULL。

空值可能很难使用,但在某些情况下它们很有意义。

假设我们有一个发票表,其中的列" PaidDate"具有日期值。在发票付款之前,我们在该栏中输入了什么(假设我们事先不知道何时付款)?不能为空字符串,因为这不是有效日期。给它指定一个任意日期(例如1/1/1900)是没有意义的,因为该日期根本不正确。似乎唯一合理的值是NULL,因为它没有值。

在数据库中使用空值有一些挑战,但是数据库可以很好地处理它们。真正的问题是当我们从数据库中将空值加载到应用程序代码中时。那就是我发现事情变得更困难的地方。例如,在.NET中,强类型数据集中的日期(模仿数据库结构)是一种值类型,并且不能为null。因此,我们必须构建变通办法。

如果可以,请避免使用null,但不要排除null,因为它们有有效的用途。

除了使用" N / A"或者" N / K"或者空字符串作为单独的表外,还有另一种选择。

例如。无论我们是否知道客户的电话号码:

CREATE TABLE Customer (ID int PRIMARY KEY, Name varchar(100) NOT NULL, Address varchar(200) NOT NULL);
CREATE TABLE CustomerPhone (ID int PRIMARY KEY, Phone varchar(20) NOT NULL, CONSTRAINT FK_CustomerPhone_Customer FOREIGN KEY (ID) REFERENCES Customer (ID));

如果我们不知道电话号码,我们只是不向第二张表添加一行。

一个陷阱,如果我们使用的是Oracle数据库。如果将空字符串保存到CHAR类型列中,则Oracle会在不询问的情况下将值强制为NULL。因此,要避免在Oracle的字符串列中使用NULL值可能会非常困难。

如果我们使用的是NULL值,请学习使用SQL命令COALESCE,尤其是对于字符串值。然后,我们可以防止NULL值传播到编程语言中。例如,假设一个人有一个FirstName,MiddleName和FamilyName,但是我们想返回一个字段;

SELECT FullName = COALESCE(FirstName + ' ', '') + COALESCE(MiddleName+ ' ', '') + COALESCE(FamilyName, '') FROM Person

如果不使用COALESCE,则如果任何列包含NULL值,则返回NULL。

我认为我们将概念数据建模与物理数据建模混淆了。

在CDM中,如果对象具有可选字段,则应该对该对象进行子类型化,并在该字段不为null时创建一个新对象。这就是CDM中的理论

在物理世界中,我们对现实世界做出了各种妥协。在现实世界中,NULLS远比罚款更好,它们是必不可少的

相关问题:如何在数据库中强制执行数据完整性规则?

我最初从许多几乎零个nullalbe字段的小表开始。然后,我了解了LINQ to SQL IsDiscriminator属性,并且LINQ to SQL仅支持单表继承。因此,我将其重新设计为具有很多nullalbe字段的单个表。

从技术上讲,在关系数据库所基于的关系数学中,空值是非法的。因此,从纯粹的技术,语义关系模型的角度来看,不,它们并不可行。

在现实世界中,非规范化和对该模型的某些违反都是可以的。但是,总的来说,空值指示我们应该更仔细地查看整体设计。

我总是非常警惕空值,并尽可能尝试将它们归一化。但这并不意味着它们有时并不是最佳选择。但是我肯定会倾向于"没有空值",除非我们真的确定在特定基础上使用空值会更好。

归结为归一化与易用性和性能问题。

如果我们要坚持完整的规范化规则,那么最终我们会写出类似以下内容的内容:

从客户c中选择c.id,c.lastname,.......

在c.id = cpn.customerid上左加入customerphonenumber cpn
在c.id = ca.customerid上左加入customeraddress ca
在c.id = cpn2.customerid上左加入customerphonenumber2 cpn2
等等等等

我认为问题归结于我们解释NULL值表示什么。是的,对于NULL值有很多解释,但是绝对不应使用此处发布的某些解释。 NULL的真实含义由应用程序上下文决定,绝不应该只包含一件事。例如,一个建议是出生日期字段为NULL表示该人还活着。这很危险。

简而言之,请定义NULL并坚持使用。我用它来表示"此字段中的值目前未知"。这意味着并且仅此而已。如果我们需要其他含义,则需要重新检查数据模型。

我同意上面的许多答案,并且还认为在适当的情况下,可以在规范化的架构设计中使用NULL,尤其是在我们可能希望避免使用某种"魔数"或者默认值的情况下,而NULL可能是误导!

但最终,我认为需要仔细考虑使用null的情况(而不是默认情况下),以避免上面答案中列出的某些假设,尤其是在假定NULL为"无"或者"空","未知"的情况下。 "或者"尚未输入值"。

空的岩石。如果在某些情况下没有必要,SQL将不具有IS NULL和IS NOT NULL作为特殊情况的运算符。 NULL是概念通用性的根,其他所有内容都不是NULL。只要有可能缺少但不会遗漏数据值,就可以自由使用NULL。如果默认值始终始终正确,则默认值只能补偿NULL。例如,如果我有一个单一字段" IsReady",则使该字段具有默认值false和NULL的默认值可能是很有意义的,但这隐式断言我们知道什么还没有准备好,实际上我们可能没有这样的知识。在工作流场景中,可能决定是否准备就绪的人还没有机会发表自己的意见,因此默认的false可能实际上很危险,导致他们忽略了似乎具有已被制作,但实际上仅是默认设置。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

顺便说一句,在中间名缩写的例子中,我父亲没有中间名,因此他的中间名缩写为NULL而不是空格,空格或者星号,除非在军队中,他的中间名缩写为NMI = No Middle Initial。那有多傻?

对于NULL的使用有几种不同的反对意见。一些反对意见是基于数据库理论的。从理论上讲,理论与实践之间没有区别。在实践中,有。

完全标准化的数据库完全可以完全没有NULLS,这是事实。必须遗漏数据值的任何地方都是可以保留整行而不会丢失信息的地方。

实际上,将表分解到这种程度并没有太大的用处,并且对数据库执行简单的CRUD操作所需的编程变得更加乏味且容易出错,而不是更少。

在某些地方使用NULL可能会引起问题:本质上,这些问题围绕以下问题进行:丢失数据的真正含义是什么? NULL真正传达的所有信息是,给定字段中没有存储任何值。但是,应用程序程序员从丢失的数据中得出的推论有时是不正确的,这会导致很多问题。

  • 该数据在这种情况下不适用。例如配偶的单身姓氏。
  • 数据输入表单的用户将字段留空,并且应用程序不需要在该字段中输入。
  • 数据已从其他数据库或者文件复制到数据库,并且源中缺少数据。
  • 外键中编码有一个可选关系。
  • 空字符串存储在Oracle数据库中。

出于各种原因,位置中的数据可能会丢失。这里有一些:

以下是一些有关何时避免使用NULL的准则:

如果在正常的预期编程过程中,查询编写者必须编写大量ISNULL,NV,COALESCE或者类似的代码,以用有效值代替NULL。有时,最好在存储时进行替换,前提是要存储的是"真实"。

如果由于计数包含NULL的行而导致计数可能关闭。通常,可以通过仅选择count(MyField)而不是count(*)来避免这种情况。

这是一个让我们更好地习惯NULL并进行相应编程的地方:每当我们开始使用外部联接时,例如LEFT JOIN和RIGHT JOIN。与内部联接不同的是,外部联接后面的全部要点是当缺少某些匹配数据时获取行。丢失的数据将以NULLS形式给出。

我的底线是:不要在不理解理论的情况下忽略理论。但是要学习何时脱离理论以及如何遵循理论。

尽管从技术上讲,NULL作为字段值是可以的,但它们却经常被人们皱眉。根据数据写入数据库的方式,有可能(并且很常见)在字段中以空字符串值结尾而不是NULL。因此,任何将此字段作为WHERE子句的一部分的查询都需要处理这两种不必要的击键场景。

null表示没有值,而0则没有,如果我们看到0则不知道含义,如果看到null则表示它是缺失值

我认为null更清楚,0和''令人困惑,因为它们不能清楚地显示出存储值的意图

  • 没有东西等于null,也没有东西等于或者大于null,因此如果要进行批量比较,则必须将null设置为占位符值。
  • 这对于可能在联接中使用的复合键也是一个问题。如果自然键包含可为空的列,则我们可能需要考虑使用合成键。
  • 空值可能会超出计数范围,这可能不是我们想要的语义。
  • 可以联接的列中的空值将消除内部联接中的行。通常,这可能是理想的行为,但它可能会给进行报告的人埋下大象的陷阱。

空值的主要问题在于它们具有特殊的语义,这些语义可以通过比较,聚集和联接产生意外结果。

  • 可能存在或者可能不存在联合实体的可选关系。空是在外键列上表示可选关系的唯一方法。
  • 我们可能希望使用null来减少计数的列。
  • 可能存在或者可能不存在的可选数字(例如货币)值。数字系统中没有"未记录"的有效占位符值(尤其是在零是合法值的情况下),因此,null确实是唯一的好方法。

null还有很多其他的细微之处。 Joe Celko的《 SQL for Smarties》一书中有整整一章,是一本好书,仍然值得一读。使用空值是一个很好的解决方案的地方的一些示例是:

  • 带有参考表的FK的代码字段上的"未记录"值。使用占位符值,这样我们(或者后面的一些随机业务分析师)在对数据库进行查询时,不会无意中从结果集中删除行。
  • 没有输入任何内容的描述字段-空字符串('')可以很好地解决这个问题。这省去了将空值视为特殊情况的麻烦。
  • 报告或者数据仓库系统上的可选列。对于这种情况,请在维度中为"未记录"创建一个占位符行,然后加入该行。这样可以简化查询,并且可以与即席报告工具很好地配合使用。

我们可能希望避免使用null的地方的一些示例,因为它们可能会引起细微的错误。

同样,Celko的书很好地处理了这个问题。

where bitfield in (1,0)

不要低估通过使字段为NULL可创建的复杂性。例如,以下where子句看起来将匹配所有行(位只能是1或者0,对吧?)

select * from mytable
where id not in (select id from excludetable)

但是,如果位字段可为NULL,它将丢失一些。或者接受以下查询:

select * from mytable
where id <> NULL and id <> 1

现在,如果排除表包含一个空值和一个1,则表示:

但是,对于任何id值," id <> NULL"都是false,因此它将永远不会返回任何行。这甚至使经验丰富的数据库开发人员大吃一惊。

It seems that if null is valid within the context of the attribute, then it should be allowed.

鉴于大多数人可能会因为NULL而措手不及,因此我会尽量避免使用NULL。

This is very common in Java where object references are often null.

但是null是什么意思呢?就是这样。它是"无价值的",但是有十多种不同的原因可能在那里没有价值," null"并没有给我们任何线索,在这种情况下,这意味着什么。 (尚未设置,不适用于此实例,不适用于此类型,未知,不知道,未找到,错误,程序错误,...)

有一种流派说空引用在那里也很糟糕。同样的问题:null是什么意思?

IIRC,Java同时具有" null"和" uninitialized"(尽管后者没有语法)。因此,戈斯林意识到对每种"无价值"使用"空"是愚蠢的。但是为什么只停两个呢?

作为具有30年经验的分析师/程序员,我只是说应该将NULL撤回并消除它们的痛苦。

-1、01 / 01/0001/12/31/9999和?无需花心思来处理这些讨厌的NULL所需的代码,所有这些也将足够。

我的话不要words讽。除非我们使用玩具数据库,否则NULL是不可避免的,而在现实世界中,我们无法避免使用NULL值。

只是为了说出每个人的名字,中间名和姓氏。 (中间名和姓氏是可选的,在这种情况下,NULL为我们提供)

博客列表中每个人如何使用传真,商务电话,办公电话。

NULL很好,检索时必须正确处理它们。在SQL Server 2008中,有一个稀疏列的概念,在这里我们也可以避免为NULL占用的空间。

不要将NULL与零和任何其他值混淆。人们会说这是对的。

段落数量不匹配