【问题标题】:NULL value in multi-column primary key多列主键中的 NULL 值
【发布时间】:2012-06-12 17:02:04
【问题描述】:

我有一个表,其中有几列构成主键。所存储数据的性质允许其中一些字段具有NULL 值。我的桌子是这样设计的:

CREATE TABLE `test` (
    `Field1` SMALLINT(5) UNSIGNED NOT NULL,
    `Field2` DECIMAL(5,2) UNSIGNED NULL DEFAULT NULL,
    PRIMARY KEY (`Field1`, `Field2`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;

但是,当我运行 describe test 时,它显示如下:

|| *Field* || *Type*                || *Null* || *Key* || *Default* || *Extra* 
|| Field1  || smallint(5) unsigned  || NO     || PRI   ||           ||         
|| Field2  || decimal(5,2) unsigned || NO     || PRI   || 0.00      ||         

我在插入 NULL 值时不断收到错误消息。

列 'Field2' 不能为空

这是因为作为主键一部分的字段不能为空吗?除了为NULL 使用“0”之外,我还有什么其他选择?

【问题讨论】:

  • 感谢 vj shah 的链接,@Tomalak 使 excellent point 表明此限制遵循基本 SQL 原则,即由于 PRIMARY 键的部分必须从每一行与每一行进行比较,并且“ NULL 不能是比较的一部分 - 这种比较的结果将始终为 NULL”,强制 PRIMARY 键唯一性需要非空列。
  • 对于字符串,对其中一列使用空字符串(或设为默认值),这样可以毫无问题地插入一条记录。后续插入需要有一些值来确保复合键(多列主键)的唯一性。

标签: mysql null composite-primary-key


【解决方案1】:

来自 MySQL 文档:

主键

一个唯一索引,其中所有键列都必须定义为 NOT NULL。如果 它们没有被显式声明为 NOT NULL,MySQL 是这样声明它们的 隐含地(和默默地)。一张表只能有一个 PRIMARY KEY。这 PRIMARY KEY 的名称始终是 PRIMARY,因此不能用作 任何其他类型索引的名称。

https://dev.mysql.com/doc/refman/8.0/en/create-table.html

如果 Field2 可以为 NULL,我质疑您为什么需要它作为主键的一部分,因为您需要 Field1 在所有行中都是不同的。所以 Field1 本身应该足以作为主键。您可以在 Field2 上创建不同类型的索引。

【讨论】:

  • 令人惊讶的是,它允许使用定义为接受空值的列创建主键。
  • 这是我一直在寻找但没有找到的定义。谢谢你。事实上,我现在有 12 列构成主键。其中 5 个值可以为空。这是一种缓存策略,其中并非所有值都需要在已兑现的请求中。我的想法是复合主键比使用自动增量值作为 PK 并在所有其他键上添加唯一索引更便宜。看来我必须走那条路。
  • @Girish 我刚刚遇到了这个问题,我也想要一个可以为空的字段。在我的情况下,PK 是两个字段,其中一个可以为空,但我最多希望有第二个字段为 NULL 的一行,所以这应该是一个有效的 PK。恕我直言,这是 MySQL 的失败规范。
  • 我有同样的问题,我需要一个两列 pk,一个空。此列也是可能链接到另一个表的外键。如果没有 null 选项,我必须用一个值设置它,它破坏了外键。
  • 我没看到。显然 Field1 -> 5 和 Field2 -> null 与 Field1 -> 5 和 Field2 -> 3 不同。因此,这可用于识别明显不同的对。我在谷歌搜索后发现了这个线程,因为我处于那种情况,并且不明白为什么我不能在主键中使用 NULL...
【解决方案2】:

主键用于使列既唯一又不为空

为了插入 NULL 值,将 field2 设为 UNIQUE

唯一约束使字段删除重复但允许 null

【讨论】:

  • 这个问题的答案,谢谢。接受的答案是错误的。
  • @singe3 好吧,问题不是如何创建具有NULL 值的索引,而是为什么我的主键中不能有NULL 值。我很高兴唯一键让您拥有 NULL 字段的信息对您有所帮助,但它不能回答问题。接受的答案确实如此。
【解决方案3】:

主键声明该列不能有NULL 值。所以用于定义复合主键的列不会是NULL

Oracle 服务器还比较复合主键定义中使用的所有列的组合。如果您的所有列现有数据(例如 x,y)与新添加的行匹配,则会引发 Unique Constraint Violated 错误。

此外,看看这个线程: What's wrong with nullable columns in composite primary keys?.

此链接提供了有关复合键中可能存在 NULLABLE 列的宝贵信息!

【讨论】:

  • 感谢您的意见。不过,我不在 Oracle 上,而是在 MySQL 上。
【解决方案4】:

您可以像这样使用唯一键:

mysql> CREATE TABLE `test` (
    ->     `Field1` SMALLINT(5) UNSIGNED NOT NULL,
    ->     `Field2` DECIMAL(5,2) UNSIGNED NULL DEFAULT NULL,
    ->     UNIQUE KEY (`Field1`, `Field2`)
    -> )
    -> COLLATE='latin1_swedish_ci'
    -> ENGINE=InnoDB;
Query OK, 0 rows affected (0.03 sec)

mysql> 
mysql> desc test
    -> ;
+--------+-----------------------+------+-----+---------+-------+
| Field  | Type                  | Null | Key | Default | Extra |
+--------+-----------------------+------+-----+---------+-------+
| Field1 | smallint(5) unsigned  | NO   | MUL | NULL    |       |
| Field2 | decimal(5,2) unsigned | YES  |     | NULL    |       |
+--------+-----------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

【讨论】:

    【解决方案5】:

    您可以使用唯一键,请查看此链接,它们适用于空值

    http://www.xaprb.com/blog/2009/09/12/the-difference-between-a-unique-index-and-primary-key-in-mysql/

    【讨论】:

      猜你喜欢
      • 2019-04-20
      • 1970-01-01
      • 2014-06-13
      • 2016-05-06
      • 1970-01-01
      • 1970-01-01
      • 2014-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多