枚举和集合时MySQL中重要的数据类型,有些场景下使用它们能起到事半功倍的作用。

 关于MySQL其它的数据类型,大家点击 [MySQL的数据类型] 进行了解,这里就不进行赘述了。

枚举和集合

 枚举,其实就是“单选”类型,对应界面或表单中的“单选项”的数据值。

enum('选项1','选项2','选项3',...);

 set就是“多选”类型,对应于界面或表单的“多选项”的数据值。

set('选项值1','选项值2','选项值3', ...);

 看下面的例子:

-- 创建一个包含char,集合,枚举的表
mysql> create table votes\c
mysql> create table votes (
    ->   username varchar(32),
    ->   hobby set('Java', 'MySql', 'Python', 'C', 'C++'),
    ->   gender enum('男', '女')
    -> );

-- 添加元素
mysql> insert into votes values('xucc', 'C,Java,MySql', '男');
Query OK, 1 row affected (0.05 sec)

mysql> select * from votes;
+----------+--------------+--------+
| username | hobby        | gender |
+----------+--------------+--------+
| xucc     | Java,MySql,C | 男     |
+----------+--------------+--------+
1 row in set (0.00 sec)

 枚举类型在定义的时候,会提供若干的选项,但是最终在存储值时,只能存储提供的选项中的一个。

 而且,出于效率考虑,表中其实存储的是一个数字。枚举的每个选项,其实对应的是一个数字,从1开始,每次递增,最多到65535。

 所以我们在定义插入枚举元素的时候,可以用数据代替。

-- 向枚举类型变量中插入枚举选项的编号
mysql> insert into votes(gender) values(1);
Query OK, 1 row affected (0.06 sec)

mysql> select * from t1;
+----------+--------------+--------+
| username | hobby        | gender |
+----------+--------------+--------+
| xucc     | Java,MySql,C | 男     |
| NULL     | NULL         | 男     |
+----------+--------------+--------+
2 rows in set (0.00 sec)

 虽然插入美剧选项的编号看起来方便的多,但是不建议这么做,因为它严重的破环了程序的可读性。

 集合在定义的时候,提供了很多的集合选项,但是在插入集合元素时,我们可以一次选择多个集合选项。

 和枚举一样,集合也有同样的设定。出于效率考虑,集合实际存储的也是“数字”。但是因为集合是一个多选数据,所以集合选项对应的数据的编号是:1,2,4,8,16…64。

2. 集合枚举的查询

 我们先创建如下的表:

mysql> select * from votes;
+----------+------------+--------+
| username | hobby      | gender |
+----------+------------+--------+
| Tom      | Java,C++   | 男     |
| Jack     | C          | 男     |
| Alice    | Java,MySql | 女     |
| David    | MySql      | 男     |
+----------+------------+--------+

mysql> desc votes;
+----------+----------------------------------------+------+-----+---------+-------+
| Field    | Type                                   | Null | Key | Default | Extra |
+----------+----------------------------------------+------+-----+---------+-------+
| username | varchar(32)                            | YES  |     | NULL    |       |
| hobby    | set('Java','MySql','Python','C','C++') | YES  |     | NULL    |       |
| gender   | enum('男','女')                        | YES  |     | NULL    |       |
+----------+----------------------------------------+------+-----+---------+-------+

 对于枚举数据的查询我们直接使用where值匹配即可。

mysql> select * from votes where gender='男';
+----------+----------+--------+
| username | hobby    | gender |
+----------+----------+--------+
| Tom      | Java,C++ | 男     |
| Jack     | C        | 男     |
| David    | MySql    | 男     |
+----------+----------+--------+
3 rows in set (0.00 sec)

 但是对于set数据的查询如果也使用where值匹配就会发生如下结果:

mysql> select * from votes where hobby='MySql';
+----------+-------+--------+
| username | hobby | gender |
+----------+-------+--------+
| David    | MySql | 男     |
+----------+-------+--------+
1 row in set (0.00 sec)

 明显hobby包括MySQL的有 Tom和David,但是查询结果只给出了Alice,这是因为where只会显示唯一值匹配成功的,而set集合数据可以包含多个集合选项,所以Alice就匹配失败了。

 使用 find_in_set 就不会发生这样的结果。

find_in_set(sub,str_list);
-- 在字符串集合str_list中查找包含指定子字符串sub的行。

 看下面的例子:

mysql> select * from votes where find_in_set('MySql', hobby);
+----------+------------+--------+
| username | hobby      | gender |
+----------+------------+--------+
| Alice    | Java,MySql | 女     |
| David    | MySql      | 男     |
+----------+------------+--------+

 所以以后在集合的查询中我们应该使用find_in_set。