MySQL UNIQUE KEY 唯一键

在本文中,我们介绍 MySQL 中如何使用唯一键/唯一索引保证一列或几列的值是唯一的。

在 MySQL 中,我们可以在一个表上定义很多约束,比如主键约束外键约束。唯一键也是一个常用的约束,用来保证表中的一列或几列的中的值是唯一的。

我们在很多系统中都用到唯一键约束,例如:

  • 用户表中有登录名或电子邮件列是唯一的。
  • 产品表中的产品编号列是唯一的。
  • 订单表中有订单编号列是唯一的。
  • 每天的统计报表中将 年、月、日 三个列作为组合唯一键。

与主键相比,主键用于表示一个行的唯一性,主键的一般采用一个与业务无关的值,比如自增值,UUID 等。而唯一键一般用于约束与业务相关的数据的唯一性。

主键列不能包含 NULL 值,而唯一键列可以包含 NULL 值。

在 MySQL 中,KEYINDEX 的同义词。一个唯一键对应了一个唯一索引。

UNIQUE 语法

要定义唯一键,请使用 UNIQUE 关键字。您可以在创建表的时候定义唯一键或者创建表后通过修改表增加一个唯一键。

定义一列为唯一键

这里是创建表时定义一列为唯一列的语法:

CREATE TABLE table_name(
    ...,
    column_name data_type UNIQUE,
    ...
);

定义多列为唯一键

如果唯一键包含多个列,请使用如下语法:

CREATE TABLE table_name(
   column_name1 column_definition,
   column_name2 column_definition,
   ...,
   [CONSTRAINT constraint_name]
      UNIQUE(column_name1,column_name2)
);

这里:

  • UNIQUE 关键子后的括号中包含了逗号分隔的多个列。
  • CONSTRAINT constraint_name 用于定义一个约束的名称。 它是可选的。如果不定义约束名称, MySQL 会自动为他生成一个。

添加唯一键语法

我们也可以向已有的表中添加一个唯一键。这是添加唯一键的语法:

ALTER TABLE table_name
ADD [CONSTRAINT constraint_name] UNIQUE (column_list);

注意,如果现有表中的要设置为唯一键的列中已有重复数据,MySQL 服务器会返回错误。

删除唯一键语法

要从表上删除唯一键,你可以使用修改表语句或者删除索引语句:

  • ALTER TABLE table_name DROP CONSTRAINT constraint_name
  • ALTER TABLE table_name DROP INDEX index_name
  • DROP INDEX index_name ON table_name

UNIQUE 实例

让我们看一些实际的例子来了解唯一键约束的用法。

首先,我们首先创建一个演示表 user_hobby,它有一个包含了 2 列的唯一键:

DROP TABLE IF EXISTS user_hobby;
CREATE TABLE `user_hobby` (
  `hobby_id` INT NOT NULL AUTO_INCREMENT,
  `user_id` INT NOT NULL,
  `hobby` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`hobby_id`),
  CONSTRAINT `unique_user_hobby` UNIQUE(`user_id`, `hobby`)
);

这里,我们定义了一个名字为 unique_user_hobby 唯一约束,它包含了 user_idhobby 2 列。

然后,我们插入两行测试数据:

INSERT INTO `user_hobby` (`user_id`, `hobby`)
VALUES (1, 'Football'), (1, 'Swimming');

现在我们查看一下表中的数据:

SELECT * FROM user_hobby;
+----------+---------+----------+
| hobby_id | user_id | hobby    |
+----------+---------+----------+
|        1 |       1 | Football |
|        2 |       1 | Swimming |
+----------+---------+----------+
2 rows in set (0.00 sec)

唯一约束

让我们再插入一行和已有 user_idhobby 列相同的数据

INSERT INTO `user_hobby` (`user_id`, `hobby`)
VALUES (1, 'Football');

MySQL 返回了错误:ERROR 1062 (23000): Duplicate entry ‘1-Football’ for key ‘user_hobby.unique_user_hobby’。

这里唯一键约束 unique_user_hobby 避免了插入重复的数据。

删除唯一键

让我们通过下面的语句删除唯一键:

DROP INDEX unique_user_hobby ON user_hobby;

你需要提供约束名称以供删除。如果你不知道它的名字或者创建唯一键的时候未指定约束名,请使用 SHOW INDEX 语句显示一个表中的所有的索引名:

SHOW INDEX FROM user_hobby;
+------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table      | Non_unique | Key_name          | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| user_hobby |          0 | PRIMARY           |            1 | hobby_id    | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| user_hobby |          0 | unique_user_hobby |            1 | user_id     | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| user_hobby |          0 | unique_user_hobby |            2 | hobby       | A         |           0 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
3 rows in set (0.01 sec)

注意,这里的 key_name 列中值就是约束名。

唯一键与 NULL 值

不像主键,唯一键允许其中的列接受 NULL 值。但是,NULL 值会破坏唯一键约束。也就是唯一键对 NULL 值无效。让我们看一下下面的例子。

现在我们修改一下刚刚的建表语句,其中允许 hobby 列为 NULL:

DROP TABLE IF EXISTS user_hobby;
CREATE TABLE `user_hobby` (
  `hobby_id` INT NOT NULL AUTO_INCREMENT,
  `user_id` INT NOT NULL,
  `hobby` VARCHAR(45),
  PRIMARY KEY (`hobby_id`),
  CONSTRAINT `unique_user_hobby` UNIQUE(`user_id`, `hobby`)
);

让我们插入两行一样的数据:

INSERT INTO `user_hobby` (`user_id`, `hobby`)
VALUES (1, NULL), (1, NULL);

然后让我们看一下表中的数据:

SELECT * FROM user_hobby;
+----------+---------+-------+
| hobby_id | user_id | hobby |
+----------+---------+-------+
|        1 |       1 | NULL  |
|        2 |       1 | NULL  |
+----------+---------+-------+
2 rows in set (0.00 sec)

我们看到了唯一键的两列出现了重复的数据。NULL 让唯一键失效了。

结论

在本文中,我们学习了在 MySQL 中唯一键/索引的用法。以下是本文的要点内容:

  • 唯一键用来保证表中的一列或几列的中的值的唯一性。
  • 请使用 UNIQUE 关键字定义唯一键。
  • 唯一键列可以为 NULL,而主键不可以为 NULL