【问题标题】:What to use instead of Null if no data is present in SQL?如果 SQL 中没有数据,使用什么来代替 Null?
【发布时间】:2016-04-26 12:50:46
【问题描述】:

我是数据库设计的新手,据我所知,使用null 值作为没有当前数据的表示不是一个好主意,我现在遇到的问题是我不知道如何表示没有当前数据而不是null

例如,我有一个用户表和一个FavoritColor 表,用户有一个名为 FC 的列,它是 FavoritColor 表的 ID 的键。现在我让用户可以不选择颜色,我该如何注意,如果用户选择不选择颜色,FC 列会填充什么?

【问题讨论】:

标签: mysql sql null


【解决方案1】:

NULL 是一个非常适合使用的值。如果您担心默认值,请确保使用OUTER JOIN 并且(无论如何,对于 SQL Server)您可以执行以下操作:

SELECT user_table.name, COALESCE(preferences.color_preference, 'DEFAULT_VALUE') FROM user_table LEFT OUTER JOIN preferences ON user_table.id = preferences.id;

这种类型的查询将允许您设置默认值并将 NULL 存储为首选颜色,如果 color_preference 为 NULL 或首选项表中没有行,您将在这种情况下获得默认值。

您说“如果用户选择不选择颜色,FC 列将填充什么?”。我问,你为什么在乎?他们要么指定了最喜欢的颜色,要么没有指定。您是否关心他们是否可以选择指定喜欢的颜色但没有告诉您?

【讨论】:

    【解决方案2】:

    NULL 是 SQL 中没有数据的“THE”表示,所以我建议你这样使用它。

    而且你总是可以在列中插入 NULL,没有理由不这样做。 如果您出于我无法理解的原因真的不想使用 NULL,我认为“无数据”的(下一个)最合乎逻辑的表示将是一个空字符串('')

    但同样,我会坚持标准...... NULL。

    【讨论】:

    • 为了迂腐,你不能“总是将 NULL 插入一列”,例如你不能将 NULL 插入到具有 NOT NULL 属性的列中。
    【解决方案3】:

    NULL 通常表示“未知”,这就是为什么'Ellen' <> NULL 不会导致TRUE,而是NULL不知道我们仍然不知道的值是否是 'Ellen'。一个例子是中间名;只要该字段为空,我们就不知道 Mary 的中间名是否是 Ellen。

    不过,我们经常使用NULL 来表示“不适用”,例如产品表中的建议零售价 - 有些产品根本没有。所以我们知道没有 RRP,它不是“未知”,但我们仍然使用NULL。我们还能做什么?改用 0 - 然后在我们的网上商店错误地显示建议零售价为零美元?还是加个标志has_rrp?一个内容的两列? NULL 通常是更简单的解决方案。

    然后,我们可以使用NULL 来表示“没有价值”。说用户表中的图像。有些用户只是在我们的数据库中没有照片,因此该值保持为空。除了 NULL 对于二进制数据为空之外,没有其他值。我们不能在其中放置一个零,因为该列应该包含图像数据,例如 jpeg 数据等。

    还有一些其他方法可以表示单个字段的“无数据”。在图像示例中,我们可以添加一个具有 1:1 关系的 user_image 表,并且记录是否存在。对于字符串,我们会使用 '',对于数字,我们有时(并非总是)可以使用零。对于日期,例如在包含过去和未来价格以及 from_date 和 to_date 的价格表中,人们有时会输入极端日期(0001-01-01、9999-12-31)以避免复杂的查询。

    对于您的 ID,我们还有一个选择:在另一个表中设置一个“无值”的 ID 和相应的条目。只要我们不希望对“没有价值”进行任何特殊处理,这是一个很好的解决方案。在您的示例中,您可以在 GUI 中显示带有“黑色”、“红色”、“蓝色”、...和“无颜色”的组合框,您可以像选择“蓝色”一样轻松选择“无颜色” '。但是如果你想要特殊待遇,那么你会遇到and color_id <> (select id from colors where value = 'no color')之类的查询,这可能会很烦人。

    顺便说一句,有时人们甚至将NULL 用于“所有值”。假设您有一张表格,其中包含每家商店的产品价格。将 shop_id 设为 NULL,您就有了所有商店的默认价格,填写 shop_id,您就有了商店特定的价格。

    NULL 通常需要特殊处理,例如使用IS 而不是=、外连接和COALESCE(color, 'no color') 等构造。这本身既不好也不坏。如果您想在用户表中计算不同的最喜欢的颜色,那很好。 COUNT(DISTINCT color) 不会计算“没有最喜欢的颜色”为 NULL,您只会计算最喜欢的颜色。

    毕竟这是一个决定。您需要区分“尚不知道”和“知道没有价值适用”吗?你想处理“红色”以外的“无色”吗? NULL 表示“无价值”一个选项,它经常被这样使用。确定它是否适合您的情况。没有规定不能使用 NULL 来表示“没有价值”。

    【讨论】:

      【解决方案4】:

      建议:

      1) 从 users 表中删除 FC 列,并添加一个关系表来模拟用户与其喜欢的颜色之间的关系,例如 UsersFavoritColor。现在通过假设未出现在UsersFavoritColor 表中的用户实际上没有喜欢的颜色来应用closed world assumption

      2) 添加另一个表 UsersWhoHaveNoFavoritColor,仅包含人员标识符,确保两个表中不能有同一个人。如果您需要对更多关系建模,请添加更多表,例如UsersWhoAreKnownToHaveNoFavoritColorUsersWhoAreKnownToHaveAFavoritColorButRefusedToTellUs

      3) 使用合适的默认值表示“无颜色”(如果可用)。

      【讨论】:

      • 最喜欢的颜色出现在用户表中,而不是相反。您的第二个建议似乎设计过度,确保一个人只出现在这些表之一中需要应用程序逻辑或触发器。
      • @Arth:我误解了设计,现在已修复。所需的“工程”程度与所选 DBMS 的缺陷有关,例如当支持CREATE ASSERTION 时,则不需要“工程”。
      • 我认为你的断言 #2 被过度设计了。为每个案例添加一个表格很疯狂,IMO
      • 好吧,如果我们在火星上,我们都会死于缺氧,但我没有随身携带氧气罐。如果整天都在为所有事情找到完美的解决方案,我们可以怎么办,但在某些时候你必须让它发挥作用,对吧?
      【解决方案5】:

      这是一个概念性问题,在placeslot 中有详细说明,包括SO。这取决于企业如何看待您的数据。

      假设您对调查问卷有疑问,或者用户偏好与用户相关联的最喜欢的颜色。您的数据库表包含 user_id 和特定颜色的十六进制。数据库设计者使用 NULL 作为一个值来表明用户还没有对它最喜欢的颜色表达任何想法。假设用户选择了一种颜色,然后有一个重置按钮。在这种情况下,您可能希望有一个空字符串而不是 NULL 值,这标志着完全没有首选项和删除现有首选项之间的区别。

      【讨论】:

        【解决方案6】:

        OP 发现 "... 使用 null 值表示没有当前数据不是一个好主意,..."

        (这可能是基于意见的。)

        我完全不同意这种说法。 NULL 值有一些显着的优势。使用 SQL 为 NULL 值提供的内置本机支持是一个非常好的主意。

        通常,NULL 值被描述为表示“未知”值。

        是的,在处理 NULL 值时需要注意一些怪癖。与 NULL 值的相等或不相等比较返回 NULL,而不是 TRUE 或 FALSE。我们只需要注意,在 SQL 中,布尔逻辑是三值的,NULL 将 从不 等于 TRUE,从不 等于 FALSE。

        这些怪癖实际上是使 NULL 值如此强大的原因。


        如果您想使用 NULL 以外的其他机制来表示“无数据”,则需要...

        存储表示“无数据”条件的非 NULL“特殊”值,以及用于检查和操作“特殊”值的附加逻辑。

        在第二列中存储非 NULL“无数据”指示符/标志,以及与第一列一起处理第二列的填充、检查和操作的附加逻辑。

        然后您还需要在外键引用的表中提供虚拟的“无数据”行,因此外键列中的非 NULL“无数据”值有一行可以引用。这就是我认为您在问题中提出的问题...

        如果你想声明你的外键列 NOT NULL,并且在没有提供值时有一个默认值,那么这个默认值将需要引用被引用表中的一行。

        作为这种方法的演示......注意:我提倡这是一种适当的设计......只是作为使用 NULL 值表示的“解决方法”的演示“没有数据”。

         create table favcolor 
         ( id            int not null primary key
         , favcolor_name varchar(30) not null
         );
        
         create table user
         ( id            int not null primary key
         , favcolor_id   int not null default '1' comment 'fk, ref favcolor.id'
         , constraint FK_user_favcolor foreign key (favcolor_id) references favcolor(id)
         );
        
         insert into favcolor (id, favcolor_name) values (1, 'not chosen');
        

        一旦你完成了所有这些,你就会发现旧的 SQL 设计师所做的事情。将这种对“未知”、“无数据”、“未选择”的处理作为 SQL 的本机内置函数将是非常有益的。这就是为什么首先引入 NULL 值来解决这类问题。

        【讨论】:

        • “与 NULL 值的相等或不相等比较返回 NULL,而不是 TRUE 或 FALSE” - 实际上,涉及 NULL 的此类操作的计算结果为 UNKNOWN。很抱歉指出这一点,这只是您需要注意的众多“怪癖”之一:)
        • @onedaywhen:在 MySQL 中,SELECT 1 = NULL 返回 NULL。试试看。
        • 我以为您在谈论“SQL Designers of old”,他将谓词定义为“可以评估以给出真、假或未知真值的条件。”
        猜你喜欢
        • 2021-10-03
        • 2020-01-04
        • 1970-01-01
        • 2018-11-24
        • 1970-01-01
        • 2019-11-28
        • 1970-01-01
        • 1970-01-01
        • 2020-05-15
        相关资源
        最近更新 更多