MySQL 主键是否需要“NOT NULL”约束?
在 MySQL 中,主键是非常重要的概念。它描述了表中的一列,其值唯一并用于标识表中的每行数据。这是一个常见的数据库概念,每个 DBMS 都有自己的实现方式。本文将探讨 MySQL 中主键约束的一个争议问题:是否需要将主键列设置为“NOT NULL”?
阅读更多:MySQL 教程
主键约束
在 MySQL 中,主键定义用于标识每行数据并确保其唯一性。主键列不能包含 NULL 值,否则该行数据将无法标识并违反唯一性约束,因为 NULL 不等于任何值。在表定义中,可以指定主键使用 PRIMARY KEY 约束。例如:
在上面的示例中,id 列定义为主键。MySQL 明确要求主键列设置为“NOT NULL”,因此如果使用以下方式创建表,则会引发错误:
因为 NULL 值不满足主键的唯一性约束。
主键的目的
主键的目的是为了快速搜索和定位表中的行。如果主键列不唯一,则查询将返回多个行,需要在结果中查找特定行(如果存在)。如果主键列可以为 NULL,则无法将每行数据标识为唯一值。
例如,假设我们有一个名为 customers 的表,其中包含数据如下:
id | name | |
---|---|---|
1 | John Smith | john@example.com |
2 | Jane Doe | jane@example.com |
3 | Joe Bloggs | joe@example.com |
4 | NULL | jane@example.com |
5 | NULL | joe@example.com |
如果我们想查找 email 为 “jane@example.com” 的客户,我们可能会使用以下查询语句:
此查询将返回两个行:id 为 2 和 4 的行。但是我们真正想要的是 id 为 2 的行。如果 id 列定义为主键,则查询仅返回匹配的行(id 为 2)。
NOT NULL 与主键
由于主键已经自动要求不包含 NULL 值,因此将列定义为“NOT NULL”似乎没有必要。在某些情况下,让主键列接受 NULL 值可能会更有意义。
例如,在订单表中,我们可能有以下列:
- order_id:订单 ID,主键。
- customer_id:关联的客户 ID。
- created_at:订单创建时间。
- updated_at:订单更新时间。
- deleted_at:订单删除时间。如果订单未删除,则为空。
在这种情况下,让 order_id 列接受 NULL 值是有意义的,因为我们可能需要注册一个 “不存在” 的订单(即订单未创建)。此外,如果该订单已被删除,则 order_id 仍为 NULL,即使它以前有值。
因此,这种情况下的表定义将如下所示:
在上面的示例中,让 order_id 列接受 NULL 值允许我们轻松地表示订单的创建和删除状态。
但是,让主键列接受 NULL 值有一些副作用。例如,如果我们运行以下命令:
该查询将返回所有未创建的订单行。但是,由于我们使用了 order_id 列作为主键,这种情况将永远不会发生。因此,如果我们要运行此查询,则需要使用其他列作为主键,并将 order_id 列设置为只接受非 NULL 值。
总之,是否需要让主键列接受 NULL 值取决于业务需求。如果唯一标识每行数据的主键不能接受 NULL 值,则应将其定义为“NOT NULL”。否则,如果列可以接受 NULL 值并且有意义,则应该让它们接受 NULL 值。
总结
MySQL 中的主键指定了表中唯一标识每行数据的列。默认情况下,MySQL 要求主键列不接受 NULL 值。但是,在某些情况下,让主键列接受 NULL 值可能是有意义的,这取决于业务需求。在这种情况下,最好使用其他列作为主键,并将允许接受 NULL 值的列设置为“NOT NULL”。