我应该在db模式中允许空值吗?

时间:2009-06-08 16:16:35

标签: sql database database-design

我在逻辑上知道,在某些情况下,NULL值在DB模式中有意义,例如,如果未指定某些值plain。也就是说,在代码中处理DBNull往往是一种皇家的痛苦。例如,如果我正在渲染一个视图,并且我想要查看一个字符串,我希望没有值是一个空字符串,而不是“Null”,我讨厌必须围绕该场景进行编码。

此外,它使查询更容易。不可否认,你可以很容易地做“foo is not null”,但是对于初级SQL开发人员来说,不能使用“foo!= null”是违反直觉的(是的,我知道关闭ANSI空值等的选项) ,但这绝对不简单,我不喜欢远离标准。

在数据库模式中有/允许空值有什么好的理由?

15 个答案:

答案 0 :(得分:41)

允许NULLS的最重要原因是没有合理的替代方案。逻辑上,NULL值表示“未定义”。由于缺少NULLS,您最终会尝试在未定义结果的地方指定“虚拟”值,然后您必须在所有应用程序逻辑中考虑所述“虚拟”值。

我写了一篇关于在数据库中包含NULL值的原因的博客文章。你可以找到它here。简而言之,我认为NULL值是数据库设计的一个组成部分,应该在适当的情况下使用

答案 1 :(得分:11)

C.J。他的书“SQL和关系理论”(2009:O'Reilly; ISBN 978-0-596-52306-0)中的日期对NULL非常强烈。他演示了SQL中是否存在NULL会给某些查询提供错误的答案。 (该参数不适用于关系模型本身,因为关系模型不允许NULL。)

我会试着用文字总结他的例子。他提出了一个表S,其中包括SNO(供应商编号)和城市(供应商所在的城市)和一行:(S1,伦敦)。表P还具有属性PNO(部件号)和城市(产生部件的城市)和一行:(P1,NULL)。现在,他执行查询“获取(SNO,PNO)对,其中供应商和部分城市不同,或者部分城市不是巴黎(或两者)。”

在现实世界中,P1是在巴​​黎或不是巴黎的城市生产的,因此查询应该返回(S1,P1),因为部分城市要么是巴黎,要么不是巴黎。 (表P中仅仅存在P1意味着该部分有一个与之相关的城市,即使是未知的。)如果是巴黎,则供应商和部分城市是不同的。如果它不是巴黎,那么部分城市不是巴黎。但是,根据三值逻辑的规则,('London'<> NULL)计算到UNKNOWN,(NULL<>'Paris')计算到UNKNOWN,UNKNOWN或UNKNOWN减少到UNKNOWN,这不是TRUE(也不是FALSE),因此不返回该行。查询“SELECT S.SNO,P.PNO FROM S,P WHERE S.CITY< P.CITY OR P.CITY<>'Paris'”的结果是一个空表,这是错误的答案。

我不是专家,目前没有能力在这里接受职业选手。我确实认为C.J.Date是关系理论的最重要权威之一。

P.S。您也可以将SQL用作关系数据库之外的其他内容。它可以做很多事情。

答案 2 :(得分:6)

  

在数据库模式中有/允许空值有什么好的理由?

从理论的角度来看,拥有NULL意味着没有为列定义值。

在需要说“我不知道/我不在乎”的地方使用它来回答“这个专栏的价值是什么?

以下是从表现的角度提供的一些提示:

  • Oracle中,NULL未编入索引。您可以使用NULL来保存索引空间并加快查询速度,以获取您不需要索引的值。
  • Oracle中,尾随NULL不占空间。
  • 与零不同,NULL可以安全地除以。
  • NULL确实为COUNT(*)做出了贡献,但没有参与COUNT(column)

答案 3 :(得分:4)

当你的列真的有一个没有默认值的未知值时,空值很好。 如果您的专栏适用于该规则,我们无法回答。

例如,如果你有和结束日期,你可能会想要将datetime.maxvalue放入,因为默认值是null而不是null。它是完全有效的,但你必须考虑在那个和那样的事情上做报告。

答案 4 :(得分:3)

理论上,理论与实践没有区别。在实践中,有。

理论上,您可以设计一个永远不需要NULL的数据库,因为它已完全规范化。每当要省略一个值时,可以省略包含它的整行,因此不需要任何NULL。

然而,为了得到这个结果你必须经历的表分解的程度根本不值得理论美学方面的收益。通常最好让某些列包含NULLS。

可空列的良好候选者除了数据是可选的之外,您永远不会在WHERE或HAVING子句中的比较条件中使用该列。信不信由你,外键通常可以在NULLS中正常工作,以指示不存在的关系实例。 INNER JOINS将删除NULLS以及包含它们的行。

当一个值经常在布尔条件中使用时,最好设计一下,以便不会发生NULLS。否则你很容易得到神秘的结果,在SQL中,“NOT UNKNOWN”的值是“UNKNOWN”。这导致了许多人面临的错误。

答案 5 :(得分:2)

通常,如果对数据库中的列允许NULL,则该NULL值与数据库本身的结构有一些单独的含义。例如,在StackOverflow database schema中,Post表中的ParentId或Tags列的NULL表示帖子是问题还是答案。只要确保在每种情况下,其含义都有详细记录。

现在您的特别抱怨是在客户端代码中处理这些值。有两种方法可以缓解这个问题:

  • 大多数具有上述含义的案例都不应该首先回到客户端。在查询中使用NULL来收集正确的结果,但不要返回NULL列本身。

  • 对于其余的情况,您通常可以使用COALESCE()或ISNULL()函数等函数来返回更容易处理的内容。

答案 6 :(得分:1)

只要您需要指定根本没有值,null就很有用。

您可以使用幻数,但处理空值比处理魔术值更直观,并且更容易记住要处理的值。 (嗯......是-1还是99999或999999这是神奇的价值......?)

此外,魔法值没有任何真正的魔力,没有任何失败的安全措施可以阻止您使用该值。计算机不知道你不能将42与-1相乘,因为在这种情况下-1恰好是一个不合理的值,但它知道你不能将42与null相乘。

对于文本值,空字符串可以作为“无值”,但即使存在一些缺点。例如,如果您在一个字段中有三个空格,则无法始终在视觉上区分空字符串,但它们是不同的值。

答案 7 :(得分:1)

在输入原始数据时,如果信息可能不可用,则应该且必须使用空值(例如,订单上的发货日期)。

当然,在某些情况下,空值可能表明需要重新设计(在大多数字段中由大多数空条目组成的表可能未正确规范化,可能不需要包含所有空值的字段。)

不使用空值因为你的jr开发人员没有正确理解它们表明你有一个比空值更大的问题。任何不了解如何访问包含空值的数据的开发人员都需要在SQL中接受基本培训。这很愚蠢,因为没有使用触发器来强制执行数据完整性规则,因为开发人员在出现问题或没有使用连接时忘记查看它们,因为开发人员不理解它们或使用select *因为开发人员太懒而无法添加字段名称。

答案 8 :(得分:1)

除了其他答案中提到的重要原因之外,NULL对于现有产品的新版本非常重要。

向现有表添加新的Nullable列的影响相对较小。由于数据迁移,添加新的非Nullable列是一个涉及更多的过程。如果您或您的客户拥有大量数据,迁移的时间和复杂性可能会成为一个重大问题。

答案 9 :(得分:0)

拥有空值的原因

  1. 这是一种公认​​的做法,每个做数据库工作的人都知道空值是如何运作的。
  2. 它清楚地表明没有价值。

答案 10 :(得分:0)

对于它的价值,SQL-99定义了一个谓词IS [NOT] DISTINCT FROM,它返回true或false,即使操作数为NULL。

foo IS DISTINCT FROM 1234

相当于:

foo <> 1234 OR foo IS NULL

PostgreSQL,IBM DB2和Firebird支持IS DISTINCT FROM

Oracle和Microsoft SQL Server(尚未)。

MySQL有自己的运算符<=>,其工作方式与IS NOT DISTINCT FROM类似。

答案 11 :(得分:0)

答案 12 :(得分:0)

从来没有一种情况下NULL在逻辑上有意义。 NULL不是关系模型的一部分,关系理论没有像NULL这样的概念。

NULL是“有用的”,在某种意义上说,糟糕的DBMS让你别无选择,只能在物理层面使用它,那些那些蹩脚的DBMS本身与逻辑层面严重混淆,或多或少迫使它们用户也这样做。

答案 13 :(得分:0)

我同意这里的大多数答案,但是以不同的方式对其进行分析,“你不能拥有一个意味着两件事的价值”。这只是令人困惑。 0实际上是0吗?或者这是否意味着我们还不知道?等。

答案 14 :(得分:0)

如果某个实体的属性没有值,那么我们使用空值。空值不是0,但它没有任何价值。一个例子是大多数韩国名字没有中间名。如果名称属性具有名字,中间名和姓氏,则应给出特殊值null。