MySQL,最好插入 NULL 或空字符串?
Posted
技术标签:
【中文标题】MySQL,最好插入 NULL 或空字符串?【英文标题】:MySQL, better to insert NULL or empty string? 【发布时间】:2010-11-19 01:46:43 【问题描述】:我在一个网站上有一个表格,它有很多不同的领域。有些字段是可选的,而有些是强制性的。在我的数据库中,我有一个包含所有这些值的表,在用户没有放置任何数据的数据库列中插入 NULL 值或空字符串是更好的做法吗?
【问题讨论】:
【参考方案1】:使用NULL
可以区分“不放数据”和“放空数据”。
更多区别:
NULL
的LENGTH
是NULL
,空字符串的LENGTH
是0
。
NULL
s 排在空字符串之前。
COUNT(message)
将计算空字符串,但不计算 NULL
s
您可以使用绑定变量搜索空字符串,但不能搜索NULL
。这个查询:
SELECT *
FROM mytable
WHERE mytext = ?
无论您从客户端传递什么值,都不会匹配mytext
中的NULL
。要匹配NULL
s,您必须使用其他查询:
SELECT *
FROM mytable
WHERE mytext IS NULL
【讨论】:
但是您认为哪个更快? 0 或 NULL 或 "" innoDB NULL 占用的空间更少 我认为这是一个不错的答案,但它也完全忽略了问题的“最佳实践”元素,只关注切线相关的事实(NULL 排序顺序和长度?这些无关紧要) .在大多数文本数据输入类型中,没有“无响应”和“空响应”之间的区别,所以我认为这是一个值得更好回答的好问题。 NULL 在设置 UNIQUE 字段时也很有效。例如,如果您有一个像驾驶执照这样的字段来添加人的 DL 号码,而这个人没有。由于它是一个唯一字段,因此将添加没有 DL 编号的第一个人,但不会添加下一个,因为它会引发唯一约束错误。所以,NULL 更好。 @Quassnoi 啊抱歉...我的意思是,为什么将驾驶号码执照设置为唯一...?【参考方案2】:我不知道这里的最佳实践是什么,但我通常会倾向于使用 null,除非您希望 null 表示与空字符串不同的东西,并且用户的输入与您的空字符串定义相匹配。
请注意,我是说您需要定义您希望它们如何不同。有时让它们不同是有意义的,有时则不然。如果没有,只需选择一个并坚持下去。就像我说的,大多数时候我倾向于使用 NULL。
哦,请记住,如果该列为空,则记录几乎不会出现在基于该列进行选择(在 SQL 术语中具有 where 子句)的任何查询中,除非选择是当然是空列。
【讨论】:
...现在我看到了上面的答案,我认为可以肯定地说,您关心的通常区别是无数据与空数据。 :-)【参考方案3】:如果您曾经计划切换数据库,需要考虑的一件事是Oracle does not support empty strings。它们会自动转换为 NULL,您无法使用 WHERE somefield = ''
之类的子句查询它们。
【讨论】:
这对我来说听起来非常可疑,即使在你的链接上也是如此,所以我试了一下。空字段,设置为 '',oracle 忽略它。将长度报告为 null 而不是 0。这是错误的。一定有办法解决这个问题。我想我会把这个作为另一个问题发布。Steve B.
:看到这个问题:***.com/questions/1171196/…
感谢您的参考,虽然我仍然不明白其中的原因。发布为***.com/questions/1268177/…
@Steve B:这是甲骨文在 l_o_n_g 前做出的设计决定。他们无法在不破坏围绕此行为设计的大量遗留 Oracle 应用程序的情况下更改该行为。因此,Oracle 永远坚持这种设计决策(零长度字符串等同于 NULL。)
Peoplesoft(使用 Oracle DB)使用单个空格来表示空值。难以置信的愚蠢。他们还使用 0.00025 表示 FTE 为 0,因为不允许使用 0。该产品做出了不错的选择。【参考方案4】:
要记住的一件事是,NULL 可能会使您的代码路径更加困难。例如,在 Python 中,大多数数据库适配器/ORM 将 NULL
映射到 None
。
比如:
print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow
可能会导致“你好,没有 Joe Doe!”为了避免它,你需要这样的代码:
if databaserow.title:
print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow
else:
print "Hello, %(firstname) %(lastname)!" % databaserow
这会使事情变得更加复杂。
【讨论】:
在我看来,滥用数据库来“修复”代码或框架中的错误是一种(非常)糟糕的编码实践。当没有数据时,您应该只插入 NULL 并在使用时保持一致。否则,您必须使用如下语句:if(myString == null || myString = "")。当您的代码中未设置或定义对象时,您也使用 NULL 而不是某种“占位符”(我认为这是一个空字符串)。 很大程度上取决于您选择的语言。在 Python 中,"if not myString:" 测试 None 和 ""。可能主要是文化问题。 Java Guys 的“坏习惯”是充满活力的人的优雅。【参考方案5】:最好插入 NULL
以在 mysql 中的数据库中保持一致性。外键可以存储为NULL
,但不能存储为空字符串。
您将遇到约束中的 空字符串 的问题。 您可能必须插入带有 唯一空字符串 的假记录以满足外键约束。我猜这是不好的做法。
另请参阅:Can a foreign key be NULL and/or duplicate?
【讨论】:
约束问题过去曾让我感到困惑,所以这就是我“+1”这个答案的原因。 但是如果你使用 NULL 确保你永远不会得到任何空字符串。使用多种 UI 技术轻松实现。【参考方案6】:如果您在唯一索引中使用多个列,并且这些列中至少有一个是强制性的(即,必填表单字段),如果您将索引中的其他列设置为 NULL,您最终可能会出现重复的行。这是因为 NULL 值在唯一列中被忽略。在这种情况下,在唯一索引的其他列中使用空字符串以避免重复行。
唯一索引中的列: (event_type_id、event_title、日期、位置、网址) 示例 1: (1, '烧烤', '2018-07-27', null, null) (1, 'BBQ', '2018-07-27', null, null) // 允许和重复。 示例 2: (1, '烧烤', '2018-07-27', '', '') (1, 'BBQ', '2018-07-27', '', '') // 不允许,因为它是重复的。这里有一些代码:
CREATE TABLE `test` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`event_id` int(11) DEFAULT NULL,
`event_title` varchar(50) DEFAULT NULL,
`date` date DEFAULT NULL,
`location` varchar(50) DEFAULT NULL,
`url` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `event_id` (`event_id`,`event_title`,`date`,`location`,`url`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
现在插入这个看看它是否允许重复的行:
INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`,
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);
INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`,
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);
现在插入它并检查它是否不允许:
INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`,
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');
INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`,
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');
所以,这里没有对错。由您决定什么最适合您的业务规则。
【讨论】:
以上是关于MySQL,最好插入 NULL 或空字符串?的主要内容,如果未能解决你的问题,请参考以下文章
PostgreSQL - 我有啥办法可以定义一个在插入或更新时将空字符串转换为 null 的列?