MySQL的数据类型介绍

一、整型

类型 存储空(单位:字节) 取值区间(有符号) 取值区间(无符号)
tinyint 1 [ -128,127 ] [0,255]
smallint 2 [-32768 , 32767] [0,65535]
mediumint 3 [-8388608 , 8388607] [0 , 16777215]
int 4 [-2147483648 , 2147483647] [0 , 4294967295]
bigint 8 [ -9223372036854775808 , 9223372036854775807] [0 , 18446744073709551615]

1.INT类型使用建议

  • 推荐不使用unsigned
  • 自增int类型主键建议使用bigint

2.unsigned的注意事项

mysql> create table test_unsigned(a int unsigned, b int unsigned);
Query OK, 0 rows affected (0.04 sec)

mysql> insert into test_unsigned values(1, 2);
Query OK, 1 row affected (0.01 sec)

//注意这个地方就报错了!
mysql> select a - b from test_unsigned;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`test`.`test_unsigned`.`a` - `test`.`test_unsigned`.`b`)'
mysql> select b-a from test_unsigned;
+------+
| b-a  |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

// 这样可以得到负数
mysql> set sql_mode = 'no_unsigned_subtraction';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select a - b from test_unsigned;
+-------+
| a - b |
+-------+
|    -1 |
+-------+
1 row in set (0.00 sec)

3.zerofill的注意事项

对于INT(N)来说,N无论写成多大,都是占4个字节的空间,而非写成几就能存几位 N不是带代表能存多少位,只是显示宽度。例如 INT(4) 和 INT(10)其实存的东西是一样的长度。 zerofill 表示当存储的数字长度 < N 时,用数字0 填充左边,直至补满长度N 当存储数字的长度超过N时,按照实际存储的数字显示 int(N)中的N 和zerofill 配合才有意义,且仅仅是显示的时候才有意义,和实际存储没有关系,不会去截取数字的长度。

mysql> create table test_int_n(a int(3) zerofill);
Query OK, 0 rows affected (0.03 sec)

//不满 N=3时,左边用0填充
mysql> insert into test_int_n values(1);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test_int_n;
+------+
| a    |
+------+
|  001 |
+------+
1 row in set (0.00 sec)

//超过N=3的长度时,是什么数字,就显示什么数字
mysql> insert into test_int_n values(1111);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test_int_n;
+------+
| a    |
+------+
|  001 |
| 1111 |
+------+
2 rows in set (0.00 sec)

//
mysql> select a, HEX(a) from test_int_n;
+------+--------+
| a    | HEX(a) |
+------+--------+
|  001 | 1      |   -- 实际存储的还是1
| 1111 | 457    |   -- 1111对于的16进制就是457
+------+--------+
2 rows in set (0.00 sec)

4.auto_increment

自增,每张表最多一个,必须是索引的一部分

//没有指定key,创建的时候就会报错
mysql> create table test_auto_increment(a int auto_increment);
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key

//指定了key,则创建成功
mysql> create table test_auto_increment(a int auto_increment primary key);
Query OK, 0 rows affected (0.02 sec)

//插入null,意思就是自增开始,从1开始
mysql> insert into test_auto_increment values(NULL);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_auto_increment;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

//插入0,自增为2
mysql> insert into test_auto_increment values(0);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_auto_increment;
+---+
| a |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)

//插入-1,则为-1
mysql> insert into test_auto_increment values(-1);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_auto_increment;
+----+
| a  |
+----+
| -1 |
|  1 |
|  2 |
+----+
3 rows in set (0.00 sec)

//插入null,继续从目前最大的值开始自增,从2开始
mysql> insert into test_auto_increment values(NULL);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_auto_increment;
+----+
| a  |
+----+
| -1 |
|  1 |
|  2 |
|  3 |
+----+
4 rows in set (0.00 sec)

//再次插入-1 ,报错,说明-1是直接插入值,而非使用自增
mysql> insert into test_auto_increment values(-1);
ERROR 1062 (23000): Duplicate entry '-1' for key 'PRIMARY'
mysql> insert into test_auto_increment values('0');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_auto_increment;
+----+
| a  |
+----+
| -1 |
|  1 |
|  2 |
|  3 |
|  4 |
+----+
5 rows in set (0.00 sec)

//这个是一个将自增从0开始的办法,先插入-1,再把 -1 update为 0
mysql> update test_auto_increment set a = 0 where a = -1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_auto_increment;
+---+
| a |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
+---+
5 rows in set (0.00 sec)

//插入3个值,第一个是从4开始自增所以为5,第二个是直接插入100,第三个是从100开始自增所以为101
mysql> insert into test_auto_increment values(NULL), (100), (NULL);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from test_auto_increment;
+-----+
| a   |
+-----+
|   0 |
|   1 |
|   2 |
|   3 |
|   4 |
|   5 |
| 100 |
| 101 |
+-----+
8 rows in set (0.00 sec)

//插入99,因为没有99这个值,所以直接插入进去
mysql> insert into test_auto_increment values(99);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_auto_increment;
+-----+
| a   |
+-----+
|   0 |
|   1 |
|   2 |
|   3 |
|   4 |
|   5 |
|  99 |
| 100 |
| 101 |
+-----+
9 rows in set (0.00 sec)

注意:

  1. AUTO_INCREMENT 是实例启动时,取当前表的最大值,然后 +1 即为下次自增的值。(MAX + 1)
    1. 数字 0 这个值比较特殊, 插入0和插入NULL的效果是一样的,都是代表自增
    2. insert into tablename select NULL; 等价于insert into tablename values (NULL);

二、浮点型

类型 占用空间 精度 精确性
float 4 单精度 低
double 8 双精度 低
decimal 变长 高精度 非常高
  • M*G/G 不一定=M
  • float(M,D) double(M,D) decimal(M,D) 表示显示M位整数,其中D位位于小数点后面

避免使用浮点类型,因为它并不属于精确的类型。 在生产环境中,不建议使用float和double,对于财务系统或者说和钱有关的,必须使用decimal。 即使使用了decimal,但是在数值运算中还是会转成浮点来运算,而且在计算过程中会出现四舍五入的情况。

//创建一个含有decimal类型的表
mysql> show create table test_decimal \G
*************************** 1. row ***************************
       Table: test_decimal
Create Table: CREATE TABLE `test_decimal` (
  `id` int(10) NOT NULL,
  `salary` decimal(6,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

//插入一个超过范围的6位的数,在表的定义写的是decimal(6,2),代表一共6位数,其中有2位为小数
//在5.7版本可用插入,但会有waring提示;在5.6版本直接报错
//查看插入的结果,就是最接近123456的一个数
mysql> insert into test_decimal(id,salary) values(1,123456);
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> show warnings;
+---------+------+-------------------------------------------------+
| Level   | Code | Message                                         |
+---------+------+-------------------------------------------------+
| Warning | 1264 | Out of range value for column 'salary' at row 1 |
+---------+------+-------------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from test_decimal;
+----+---------+
| id | salary  |
+----+---------+
|  1 | 9999.99 |
+----+---------+
1 row in set (0.00 sec)

//插入一个不超过范围的数,则正常显示
mysql> insert into test_decimal(id,salary) values(1,1234);
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_decimal;
+----+---------+
| id | salary  |
+----+---------+
|  1 | 9999.99 |
|  1 | 1234.00 |
+----+---------+
2 rows in set (0.00 sec)

//插入一个小数超范围的数,则会四舍五入
mysql> insert into test_decimal(id,salary) values(1,1234,5678);
ERROR 1136 (21S01): Column count doesn't match value count at row 1
mysql> insert into test_decimal(id,salary) values(1,1234.5678);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from test_decimal;
+----+---------+
| id | salary  |
+----+---------+
|  1 | 9999.99 |
|  1 | 1234.00 |
|  1 | 1234.57 |
+----+---------+
3 rows in set (0.00 sec)

三、字符串类型

说明 N的含义 是否有字符集 最大长度
CHAR(N) 定长字符 字符 是 255
VARCHAR(N) 变长字符 字符 是 16384
BINARY(N) 定长二进制字节 字节 否 255
VARBINARY(N) 变长二进制字节 字节 否 16384
TINYBLOB 二进制大对象 字节 否 256
BLOB 二进制大对象 字节 否 16K
MEDIUMBLOB 二进制大对象 字节 否 16M
LONGBLOB 二进制大对象 字节 否 4G
TINYTEXT 大对象 字节 是 256
TEXT 大对象 字节 是 16K
MEDIUMTEXT 大对象 字节 是 16M
LONGTEXT 大对象 字节 是 4G

BLOB=>VARBINARY TEXT=>VARCHAR

注意事项 1.在BLOB和TEXT列上创建索引的时候,必须指定索引前缀的长度 2.varchar和varbinary前缀长度是可选的 3.blob和te列不能有默认值 4.blob和text列排序时只使用该列的前 max_sort_length个字节

1.char(N)说明

假设当前table的字符集的最大长度为W , 则char(N) 的最大存储空间为(N * W)Byte 假设使用UTF-8 ,则char(10)可以最小存储10个字节的字符,最大存储30个字节的字符,其实是另一种意义上的varchar 当存储的字符数小于N 时,尾部使用空格填充,并且填充最小字节的空格

mysql> create table test_char(a char(10));
Query OK, 0 rows affected (0.02 sec)

mysql> show create table test_char\G
*************************** 1. row ***************************
       Table: test_char
Create Table: CREATE TABLE `test_char` (
  `a` char(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> insert into test_char values('abc');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_char values('启明星');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_char values('启明星hh');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_char values('启明hh星');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_char values('启明hh星啊');
Query OK, 1 row affected (0.01 sec)

mysql> select a, length(a) from test_char;
+----------------+-----------+
| a              | length(a) |
+----------------+-----------+
| abc            |         3 |
| 启明星         |         9 |
| 启明星hh       |        11 |
| 启明hh星       |        11 |
| 启明hh星啊     |        14 |
+----------------+-----------+
5 rows in set (0.01 sec)

mysql> select a, hex(a) from test_char;
+----------------+------------------------------+
| a              | hex(a)                       |
+----------------+------------------------------+
| abc            | 616263                       |
| 启明星         | E590AFE6988EE6989F           |
| 启明星hh       | E590AFE6988EE6989F6868       |
| 启明hh星       | E590AFE6988E6868E6989F       |
| 启明hh星啊     | E590AFE6988E6868E6989FE5958A |
+----------------+------------------------------+
5 rows in set (0.00 sec)

mysql> select hex(' ');
+----------+
| hex(' ') |
+----------+
| 20       |
+----------+
1 row in set (0.00 sec)

用hexdump来比较一下:

-- 1:abc
-- 2:启明星
-- 3:启明星hh
-- 4:启明hh星
-- 5:启明ab星啊
[root@nazeebo test]# hexdump -C test_char.ibd
...
...
00006070  73 75 70 72 65 6d 75 6d  0a 00 00 00 10 00 24 00  |supremum......$.|
00006080  00 00 00 02 07 00 00 00  00 0a b5 fe 00 00 00 48  |...............H|
00006090  01 10 61 62 63 20 20 20  20 20 20 20 0a 00 00 00  |..abc       ....|
000060a0  18 00 24 00 00 00 00 02  08 00 00 00 00 0a b6 ff  |..$.............|
000060b0  00 00 00 4c 01 10 e5 90  af e6 98 8e e6 98 9f 20  |...L........... |
000060c0  0b 00 00 00 20 00 25 00  00 00 00 02 09 00 00 00  |.... .%.........|
000060d0  00 0a bb a2 00 00 00 4d  01 10 e5 90 af e6 98 8e  |.......M........|
000060e0  e6 98 9f 68 68 0b 00 00  00 28 00 25 00 00 00 00  |...hh....(.%....|
000060f0  02 0a 00 00 00 00 0a bc  a3 00 00 00 49 01 10 e5  |............I...|
00006100  90 af e6 98 8e 68 68 e6  98 9f 0e 00 00 00 30 ff  |.....hh.......0.|
00006110  5f 00 00 00 00 02 0b 00  00 00 00 0a c1 a6 00 00  |_...............|
00006120  00 4a 01 10 e5 90 af e6  98 8e 68 68 e6 98 9f e5  |.J........hh....|
00006130  95 8a 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00006140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
省略一部分输出
...
[root@nazeebo test]#

2.varchar(N)说明

mysql> create table test_varchar(a varchar(10));
Query OK, 0 rows affected (0.03 sec)

mysql> show create table test_varchar \G
*************************** 1. row ***************************
       Table: test_varchar
Create Table: CREATE TABLE `test_varchar` (
  `a` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> insert into test_varchar values('abc');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_varchar values('启明星');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_varchar values('启明星hh');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_varchar values('启明hh星');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_varchar values('启明hh星啊');
Query OK, 1 row affected (0.01 sec)

mysql> select a, hex(a) from test_varchar;
+----------------+------------------------------+
| a              | hex(a)                       |
+----------------+------------------------------+
| abc            | 616263                       |
| 启明星         | E590AFE6988EE6989F           |
| 启明星hh       | E590AFE6988EE6989F6868       |
| 启明hh星       | E590AFE6988E6868E6989F       |
| 启明hh星啊     | E590AFE6988E6868E6989FE5958A |
+----------------+------------------------------+
5 rows in set (0.01 sec)

mysql> select a, length(a) from test_varchar;
+----------------+-----------+
| a              | length(a) |
+----------------+-----------+
| abc            |         3 |
| 启明星         |         9 |
| 启明星hh       |        11 |
| 启明hh星       |        11 |
| 启明hh星啊     |        14 |
+----------------+-----------+
5 rows in set (0.00 sec)
[root@nazeebo test]# hexdump -C test_varchar.ibd
...
...
00006070  73 75 70 72 65 6d 75 6d  03 00 00 00 10 00 1d 00  |supremum........|
00006080  00 00 00 02 0c 00 00 00  00 0a c6 ab 00 00 00 51  |...............Q|
00006090  01 10 61 62 63 09 00 00  00 18 00 23 00 00 00 00  |..abc......#....|
000060a0  02 0d 00 00 00 00 0a c7  ac 00 00 00 4c 01 10 e5  |............L...|
000060b0  90 af e6 98 8e e6 98 9f  0b 00 00 00 20 00 25 00  |............ .%.|
000060c0  00 00 00 02 0e 00 00 00  00 0a cc af 00 00 00 4d  |...............M|
000060d0  01 10 e5 90 af e6 98 8e  e6 98 9f 68 68 0b 00 00  |...........hh...|
000060e0  00 28 00 25 00 00 00 00  02 0f 00 00 00 00 0a cd  |.(.%............|
000060f0  b0 00 00 00 4b 01 10 e5  90 af e6 98 8e 68 68 e6  |....K........hh.|
00006100  98 9f 0e 00 00 00 30 ff  67 00 00 00 00 02 10 00  |......0.g.......|
00006110  00 00 00 0a d2 b3 00 00  00 4c 01 10 e5 90 af e6  |.........L......|
00006120  98 8e 68 68 e6 98 9f e5  95 8a 00 00 00 00 00 00  |..hh............|
00006130  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
...

3.char和varchar的区别

char用于定长,范围0-255,如果字符数没有到达定义的长度,会在后面用空格补全存入数据库;如果超过指定长度大小,会被截断。 varchar用于变长,范围0-65535,存储时按大小存取不会补空格,超过长度会截取。 使用varchar类型时,和字符集有关,会多用1~2个字节来记录字节长度,当数据位战友的字节数小于255时,用1个字节来记录长度,当数据位战友的字节数大于255时,用2个字节来记录长度,另外一位用来记录是否为null值

MySQL每一行的最大字节数为65535 使用UTF8字符集的时候,每个字符最多占3个字节,最大长度不超过(65535-2-1)/3=21844 使用GBK字符集的时候,每个字符最多占用2个字节,最大长度不超(65535-2-1)/ 2 = 36766

4.BLOB和TEXT

在BLOB和TEXT上创建索引时,必须指定索引前缀的长度

mysql> create table test_text(a int primary key, b text, key(b));
ERROR 1170 (42000): BLOB/TEXT column 'b' used in key specification without a key length
mysql> create table test_text(a int primary key, b text, key(b(64)));
Query OK, 0 rows affected (0.02 sec)

mysql> select @@max_sort_length;
+-------------------+
| @@max_sort_length |
+-------------------+
|              1024 |
+-------------------+
1 row in set (0.00 sec)

mysql>

BLOB和TEXT列不能有默认值 BLOB和TEXT列排序时只使用该列的前max_sort_length个字节

四、集合类型enum 和 set

enum允许最多65536个值 set允许最多64个值 通过sql_mode进行约束

1.集合的插入

//创建一个表,含有enum类型,插入几条数据
//虽然enum写的是字符串,单其实存储的整型,效率还行
mysql> create table test_col(
    -> user varchar(10),
    -> sex enum('male','female')
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_col values ("tom", "male");
Query OK, 1 row affected (0.00 sec)

//插入错误的enum,会有warings,并且相应的值被截断直接为空
mysql> insert into test_col values ("tom", "xmale");
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> show warnings;
+---------+------+------------------------------------------+
| Level   | Code | Message                                  |
+---------+------+------------------------------------------+
| Warning | 1265 | Data truncated for column 'sex' at row 1 |
+---------+------+------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from test_col;
+------+------+
| user | sex  |
+------+------+
| tom  | male |
| tom  |      |
+------+------+
2 rows in set (0.00 sec)

//设置sql_mode,发现错误的enum类型是插入不进去的
mysql> set sql_mode='strict_trans_tables';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> insert into test_col values ("bob", "xmale");
ERROR 1265 (01000): Data truncated for column 'sex' at row 1
mysql> select * from test_col;
+------+------+
| user | sex  |
+------+------+
| tom  | male |
| tom  |      |
+------+------+
2 rows in set (0.00 sec)

建议业务上都设置成严格模式 另外,虽然enum写的是字符串,单其实存储的是int类型数组(相当于male=0,female=1),性能还是可以的

2.集合的排序

mysql> show create table test_col_sort\G
*************************** 1. row ***************************
       Table: test_col_sort
Create Table: CREATE TABLE `test_col_sort` (
  `user` char(10) DEFAULT NULL,
  `type` enum('aaa','zzz','bbb','yyy','fff') DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

//插入数据
mysql> insert into test_col_sort(user,type) values('user1','aaa'),('user2','bbb'),('user3','yyy'),('user4','zzz');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

//order by type 就等于按照enum里面的顺序,[0,1,2,3]
mysql> select * from test_col_sort order by type asc;
+-------+------+
| user  | type |
+-------+------+
| user1 | aaa  |
| user4 | zzz  |
| user2 | bbb  |
| user3 | yyy  |
+-------+------+
4 rows in set (0.00 sec)

//order by  cast(type as char) ,意思是将type转换为char再进行排序
mysql> select * from test_col_sort order by cast(type as char) asc;
+-------+------+
| user  | type |
+-------+------+
| user1 | aaa  |
| user2 | bbb  |
| user3 | yyy  |
| user4 | zzz  |
+-------+------+
4 rows in set (0.00 sec)

//order by concat
mysql> select * from test_col_sort order by concat(type) asc;
+-------+------+
| user  | type |
+-------+------+
| user1 | aaa  |
| user2 | bbb  |
| user3 | yyy  |
| user4 | zzz  |
+-------+------+
4 rows in set (0.00 sec)

五、日期类型

日期类型 占用字节 表示范围
DATETIME 8 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
DATE 3 1000-01-01 ~ 9999-12-31
TIMESTAMP 4 1970-01-01 00:00:00UTC ~ 2038-01-19 03:14:07UTC
YEAR 1 YEAR(2):1970-2070, YEAR(4):1901-2155
TIME 3 -838:59:59 ~ 838:59:59

1.TIMESTAMP 和 DATETIME

datetime与timestamp最大的区别在于时区

mysql> create table test_time(a timestamp, b datetime);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_time values (now(), now());
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_time;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2018-06-29 00:28:40 | 2018-06-29 00:28:40 |
+---------------------+---------------------+
1 row in set (0.00 sec)

mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| SYSTEM      |
+-------------+
1 row in set (0.00 sec)

mysql> set time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| +00:00      |
+-------------+
1 row in set (0.00 sec)

//设置了时区后,两者有了差别
mysql> select * from test_time;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2018-06-28 16:28:40 | 2018-06-29 00:28:40 |
+---------------------+---------------------+
1 row in set (0.00 sec)

2.微秒解读

MySQL5.6.4版本开始支持微秒 支持类型包括:time 、datetime与 、timestamp type_name(fsp) fsp<=6

//用法 type_name(fsp)  fsp<=6
mysql> select now(5);
+---------------------------+
| now(5)                    |
+---------------------------+
| 2018-06-28 16:34:10.64251 |
+---------------------------+
1 row in set (0.00 sec)

mysql> select now(6);
+----------------------------+
| now(6)                     |
+----------------------------+
| 2018-06-28 16:34:36.658036 |
+----------------------------+
1 row in set (0.00 sec)

// 最多支持6位精度
mysql> select now(7);
ERROR 1426 (42000): Too-big precision 7 specified for 'now'. Maximum is 6.
mysql>
mysql> create table test_time_fac (t datetime(6));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_time_fac values(now(6));
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_time_fac;
+----------------------------+
| t                          |
+----------------------------+
| 2018-06-28 16:35:04.557430 |
+----------------------------+
1 row in set (0.00 sec)

3.日期函数

函数 说明 备注
NOW 返回sql执行时的时间 如果不考虑其他因素,可以理解为写完SQL,敲下回车瞬间的时间
current_timestamp 与now一样
sysdate 返回执行函数时的时间 MySQL处理你的函数时的时间,统一SQL语句中,大于NOW
date_add(date,interval expr unit) 增加时间 可用ADD,然后unit给负数
date_sub(date,interval expr unit) 减少时间
date_format 格式化时间显示

3.1 NOW 和 SYSDATE的区别

mysql> select now(6),sysdate(6),sleep(5),now(6),sysdate(6);
+----------------------------+----------------------------+----------+----------------------------+----------------------------+
| now(6)                     | sysdate(6)                 | sleep(5) | now(6)                     | sysdate(6)                 |
+----------------------------+----------------------------+----------+----------------------------+----------------------------+
| 2018-06-29 00:38:59.002591 | 2018-06-29 00:38:59.002708 |        0 | 2018-06-29 00:38:59.002591 | 2018-06-29 00:39:04.002832 |
+----------------------------+----------------------------+----------+----------------------------+----------------------------+
1 row in set (5.00 sec)

两个now(6)都相等,因为是SQL执行时的时间(可以简单理解为按回车的时间) 两个sysdate(6)差了5秒,差不多刚好是sleep(5)的时间

3.2 date_add的使用方法

//加5天
mysql> select now(),date_add(now(), interval 5 day);
+---------------------+---------------------------------+
| now()               | date_add(now(), interval 5 day) |
+---------------------+---------------------------------+
| 2018-06-29 00:41:03 | 2018-07-04 00:41:03             |
+---------------------+---------------------------------+
1 row in set (0.00 sec)

//加负的5个月=倒退5个月
mysql> select now(),date_add(now(), interval -5 month);
+---------------------+------------------------------------+
| now()               | date_add(now(), interval -5 month) |
+---------------------+------------------------------------+
| 2018-06-29 00:41:28 | 2018-01-29 00:41:28                |
+---------------------+------------------------------------+
1 row in set (0.00 sec)

//减5个月
mysql> select now(),date_sub(now(), interval 5 month);
+---------------------+-----------------------------------+
| now()               | date_sub(now(), interval 5 month) |
+---------------------+-----------------------------------+
| 2018-06-29 00:41:43 | 2018-01-29 00:41:43               |
+---------------------+-----------------------------------+
1 row in set (0.00 sec)

3.3 date_format的用法

mysql> SELECT now(),DATE_FORMAT((select now(6)), '%H:%i:%s');
+---------------------+------------------------------------------+
| now()               | DATE_FORMAT((select now(6)), '%H:%i:%s') |
+---------------------+------------------------------------------+
| 2018-06-29 00:44:46 | 00:44:46                                 |
+---------------------+------------------------------------------+
1 row in set (0.00 sec)

3.4 字段更新时间

mysql> create table test_field_update(
    -> a int(10),
    -> b timestamp not null default current_timestamp on update current_timestamp
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> insert into test_field_update values(1, now(6));
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_field_update;
+------+---------------------+
| a    | b                   |
+------+---------------------+
|    1 | 2018-06-29 00:45:46 |
+------+---------------------+
1 row in set (0.00 sec)

//更新数据,发现相应的字段的数据也更新了,这个可以拿来用在记录记录的表更上
//当然,如果想更精确,可以使用timestamp,now(6)
mysql> update test_field_update set a=100 where a=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_field_update;
+------+---------------------+
| a    | b                   |
+------+---------------------+
|  100 | 2018-06-29 00:46:01 |
+------+---------------------+
1 row in set (0.00 sec)

六、JSON类型

  • 5.7版本开始支持
  • 原生json类型用来替代BLOB
  • json数据有效性检查:blob类型无法在数据库层做这样的约束性检查,而json类型可以
  • 查询性能的提升:查询不需要遍历所有的字符串才能找到数据
  • 支持部分属性索引:通过虚拟列的功能可以对json中的部分数据进行索引

1.JSON格式示例(wiki百科)

{
    "firstName": "John",  //Key: Value 格式
    "lastName": "Smith",
    "sex": "male",
    "age": 25,
    "address": //Key: Value;其中 Value 也是一个 Key - Value 的结构
    {
        "streetAddress": "21 2nd Street",
        "city": "New York",
        "state": "NY",
        "postalCode": "10021"
    },
    "phoneNumber": [{
            "type": "home",
            "number": "212 555-1234"
        },
        {
            "type": "fax",
            "number": "646 555-4567"
        }
    ]
}

2. JSON 和 BLOB 的对比

  • JSON:

    • JSON数据可以做有效性检查;
    • JSON使得查询性能提升;
    • JSON支持部分属性索引,通过虚拟列的功能可以对JSON中的部分数据进行索引;
  • BLOB:

    • BLOB类型无法在数据库层做约束性检查;
    • BLOB进行查询,需要遍历所有字符串;
    • BLOB做只能做指定长度的索引;
  • 5.7之前,只能把JSON当作BLOB进行存储。数据库层面无法对JSON数据做一些操作,只能由应用程序处理。

3. 结构化和非结构化

  • 结构化
    • 二维表结构(行和列)
    • 使用SQL语句进行操作
  • 非结构化
    • 使用Key-Value格式定义数据,无结构定义
    • Value可以嵌套Key-Value格式的数据
    • 使用JSON进行实现

4. json示例

mysql> create table test_json (
    -> uid int auto_increment,
    -> data json,
    -> primary key(uid)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> insert into test_json values (
    -> null, -- 自增长数据,可以插入null
    -> '{
    '> "name":"nazeebo",
    '> "age":38,
    '> "address":"CD"
    '> }'
    -> );
Query OK, 1 row affected (0.00 sec)

mysql> insert into test_json values (
    -> null,
    -> '{
    '> "name":"lowa",
    '> "age":37,
    '> "mail":"lowa@bxbb.com"
    '> }'
    -> );
Query OK, 1 row affected (0.00 sec)

// 无法插入,因为是JSON类型
mysql> insert into test_json values ( null, "今晚打老虎");
ERROR 3140 (22032): Invalid JSON text: "Invalid value." at position 0 in value for column 'test_json.data'.
mysql>
mysql> select * from test_json;
+-----+------------------------------------------------------+
| uid | data                                                 |
+-----+------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD"}      | //这个json中有address字段
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"} | //这个json中有mail字段
+-----+------------------------------------------------------+
2 rows in set (0.00 sec)

mysql>

5. json的相关函数

5.1 使用json_extract提取数据

mysql> select json_extract('[10, 20, [30, 40]]', '$[1]');
+--------------------------------------------+
| json_extract('[10, 20, [30, 40]]', '$[1]') |
+--------------------------------------------+
| 20                                         |  // 从list中抽取 下标 为1的元素(下标从0开始)
+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select
    -> json_extract(data, '$.name'), -- 提起name字段的数据
    -> json_extract(data, '$.address') -- 提取address字段的数据
    -> from test_json;
+------------------------------+---------------------------------+
| json_extract(data, '$.name') | json_extract(data, '$.address') |
+------------------------------+---------------------------------+
| "nazeebo"                    | "CD"                            |
| "lowa"                       | NULL                            |  // lowa 没有address字段,填充了NULL
+------------------------------+---------------------------------+
2 rows in set (0.00 sec)

5.2 使用json_object 将list(K-V对)封装成json格式

mysql> select json_object("name", "lm", "email", "limin@bxbb.com", "age",99);
+----------------------------------------------------------------+
| json_object("name", "lm", "email", "limin@bxbb.com", "age",99) |
+----------------------------------------------------------------+
| {"age": 99, "name": "lm", "email": "limin@bxbb.com"}           |
+----------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into test_json values (
    -> null,
    -> json_object("name", "lm", "email", "limin@bxbb.com", "age",99) -- 进行封装
    -> );
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_json;
+-----+------------------------------------------------------+
| uid | data                                                 |
+-----+------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD"}      |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"} |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"} |
+-----+------------------------------------------------------+
3 rows in set (0.00 sec)

5.3 使用json_insert 插入数据

mysql> set @j = '{ "a": 1, "b": [2, 3]}';
Query OK, 0 rows affected (0.00 sec)

mysql> select json_insert(@j, '$.a', 10, '$.c', '[true, false]');
+----------------------------------------------------+
| json_insert(@j, '$.a', 10, '$.c', '[true, false]') |
+----------------------------------------------------+
| {"a": 1, "b": [2, 3], "c": "[true, false]"}        | //存在的不受影响,例如a还是=1
+----------------------------------------------------+ //c之前不存在,则插入
1 row in set (0.00 sec)

mysql>
mysql> select * from test_json;
+-----+------------------------------------------------------+
| uid | data                                                 |
+-----+------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD"}      |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"} |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"} |
+-----+------------------------------------------------------+
3 rows in set (0.01 sec)

//  插入 addres_2
mysql> update test_json set data = json_insert(data, "$.address_2", "BJ") where uid = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_json;
+-----+--------------------------------------------------------------------+
| uid | data                                                               |
+-----+--------------------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": "CD", "address_2": "BJ"} |  //对比发现插入了 addres_2
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}               |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}               |
+-----+--------------------------------------------------------------------+
3 rows in set (0.00 sec)

5.4 使用json_merge 合并数据并返回

注意:原数据不受影响

mysql> select json_merge('{"name": "zxx"}', '{"id": 9527}');
+-----------------------------------------------+
| json_merge('{"name": "zxx"}', '{"id": 9527}') |
+-----------------------------------------------+
| {"id": 9527, "name": "zxx"}                   |
+-----------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> select
    -> json_merge(
    -> json_extract(data, '$.address'), -- json 1
    -> json_extract(data, '$.address_2')) -- jons 2
    -> from test_json where uid = 1;
+----------------------------------------------------------------------------------+
| json_merge(
json_extract(data, '$.address'),
json_extract(data, '$.address_2')) |
+----------------------------------------------------------------------------------+
| ["CD", "BJ"]                                                                     |
+----------------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                   |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------+
| Warning | 1287 | 'JSON_MERGE' is deprecated and will be removed in a future release. Please use JSON_MERGE_PRESERVE/JSON_MERGE_PATCH instead |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select
    -> JSON_MERGE_PRESERVE(
    -> json_extract(data, '$.address'), -- json 1
    -> json_extract(data, '$.address_2')) -- jons 2
    -> from test_json where uid = 1;
+-------------------------------------------------------------------------------------------+
| JSON_MERGE_PRESERVE(
json_extract(data, '$.address'),
json_extract(data, '$.address_2')) |
+-------------------------------------------------------------------------------------------+
| ["CD", "BJ"]                                                                              |
+-------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>

5.5 使用json_array_append 追加数据

mysql>  set @j = '["a", ["b", "c"], "d"]';
Query OK, 0 rows affected (0.00 sec)

mysql> select json_array_append(@j, '$[1]', 1);
+----------------------------------+
| json_array_append(@j, '$[1]', 1) |
+----------------------------------+
| ["a", ["b", "c", 1], "d"]        |  //下标为1的值,增加“1”
+----------------------------------+
1 row in set (0.00 sec)

mysql> update test_json set data = json_array_append(
    -> data,
    -> '$.address',
    -> json_extract(data, '$.address_2'))
    -> where uid = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_json;
+-----+----------------------------------------------------------------------------+
| uid | data                                                                       |
+-----+----------------------------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"], "address_2": "BJ"} |  //将address2的值添加到了address中去
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}                       |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}                       |
+-----+----------------------------------------------------------------------------+
3 rows in set (0.00 sec)

5.6 使用json_remove 从json记录中删除数据

mysql> set @j = '["a", ["b", "c"], "d"]';
Query OK, 0 rows affected (0.00 sec)

mysql>  select json_remove(@j, '$[1]');
+-------------------------+
| json_remove(@j, '$[1]') |
+-------------------------+
| ["a", "d"]              |  //删除下标为1的key和value
+-------------------------+
1 row in set (0.00 sec)

mysql> update test_json set data = json_remove(data, "$.address_2") where uid = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from test_json;
+-----+---------------------------------------------------------+
| uid | data                                                    |
+-----+---------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"]} |  // address_2 的字段删除了
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}    |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}    |
+-----+---------------------------------------------------------+
3 rows in set (0.00 sec)

6. json 字段创建索引

JSON 类型数据本身 无法直接 创建索引,需要将需要索引的 JSON数据 重新生成虚拟列(Virtual Columns) 之后,对该列进行索引

6.1 新建表的时候创建json索引

1.创建表,建表的语法中抽取data中的name, 生成新的一列,名字为gen_col
mysql> create table test_json_index(
    ->  data json,
    ->  gen_col varchar(10) generated always as (json_extract(data, '$.name')),
    ->  index idx (gen_col) -- 将gen_col 作为索引
    ->  );
Query OK, 0 rows affected (0.03 sec)

mysql> show create table test_json_index\G
*************************** 1. row ***************************
       Table: test_json_index
Create Table: CREATE TABLE `test_json_index` (
  `data` json DEFAULT NULL,
  `gen_col` varchar(10) GENERATED ALWAYS AS (json_extract(`data`,'$.name')) VIRTUAL,
  KEY `idx` (`gen_col`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

2.插入两条数据
mysql> insert into test_json_index(data) values ('{"name":"lowa", "age":38, "address":"CD"}');
Query OK, 1 row affected (0.01 sec)

mysql>  insert into test_json_index(data) values ('{"name":"nazeebo", "age":66, "address":"SZ"}');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test_json_index;
+-------------------------------------------------+-----------+
| data                                            | gen_col   |
+-------------------------------------------------+-----------+
| {"age": 38, "name": "lowa", "address": "CD"}    | "lowa"    |
| {"age": 66, "name": "nazeebo", "address": "SZ"} | "nazeebo" |
+-------------------------------------------------+-----------+
2 rows in set (0.00 sec)

3.查询的时候发现找不到记录
mysql> select json_extract(data,"$.name") as username from test_json_index where gen_col="lowa";
Empty set (0.00 sec)

4.原因是因为存储的时候连“”也存储了的
mysql>  select hex('"');
+----------+
| hex('"') |
+----------+
| 22       |
+----------+
1 row in set (0.00 sec)

mysql> select hex(gen_col) from test_json_index;
+--------------------+
| hex(gen_col)       |
+--------------------+
| 226C6F776122       |
| 226E617A6565626F22 |
+--------------------+
2 rows in set (0.00 sec)

5.所以带上双引号再去查询就可以得到正确的结果集
mysql> select json_extract(data,"$.name") as username from test_json_index where gen_col='"lowa"';
+----------+
| username |
+----------+
| "lowa"   |
+----------+
1 row in set (0.00 sec)

6.查看执行计划,使用了index的
mysql> explain select json_extract(data,"$.name") as username from test_json_index where gen_col='"lowa"' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_json_index
   partitions: NULL
         type: ref
possible_keys: idx
          key: idx
      key_len: 43
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

7.为了避免出现连双引号一起存储的情况,采用json_unquote函数进行去掉双引号创建新的表test_json_index_2
mysql> create table test_json_index_2 (
    -> data json,
    -> gen_col varchar(10) generated always as (
    -> json_unquote( -- 使用json_unquote函数进行去掉双引号
    -> json_extract(data, "$.name")
    -> )),
    -> key idx(gen_col)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> show create table test_json_index_2\G
*************************** 1. row ***************************
       Table: test_json_index_2
Create Table: CREATE TABLE `test_json_index_2` (
  `data` json DEFAULT NULL,
  `gen_col` varchar(10) GENERATED ALWAYS AS (json_unquote(json_extract(`data`,'$.name'))) VIRTUAL,
  KEY `idx` (`gen_col`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.01 sec)

8.再次插入两条记录
mysql> insert into test_json_index_2(data) values ('{"name":"lowa", "age":38, "address":"CD"}');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_json_index_2(data) values ('{"name":"nazeebo", "age":66, "address":"SZ"}');
Query OK, 1 row affected (0.00 sec)

9.再次查询,发现能正确的获取到结果集
mysql> select json_extract(data,"$.name") as username from test_json_index_2 where gen_col="lowa";
+----------+
| username |
+----------+
| "lowa"   |
+----------+
1 row in set (0.00 sec)

10.查询执行计划,发现也使用了index
mysql> explain select json_extract(data,"$.name") as username from test_json_index_2 where gen_col="lowa"\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_json_index_2
   partitions: NULL
         type: ref
possible_keys: idx
          key: idx
      key_len: 43
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

6.2 修改已存在的表创建JSON索引

1.拿之前创建好的表test_json来做实验
mysql> show create table test_json\G
*************************** 1. row ***************************
       Table: test_json
Create Table: CREATE TABLE `test_json` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `data` json DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> select * from test_json;
+-----+---------------------------------------------------------+
| uid | data                                                    |
+-----+---------------------------------------------------------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"]} |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}    |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}    |
+-----+---------------------------------------------------------+
3 rows in set (0.00 sec)

2.创建虚拟列
**注意:virtual 关键字是不将该列的字段值存储,对应的是stored**
mysql> alter table test_json
    -> add user_name varchar(32)
    -> generated always as (json_extract(data,"$.name")) virtual;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from test_json;
+-----+---------------------------------------------------------+-----------+
| uid | data                                                    | user_name |
+-----+---------------------------------------------------------+-----------+
|   1 | {"age": 38, "name": "nazeebo", "address": ["CD", "BJ"]} | "nazeebo" |
|   2 | {"age": 37, "mail": "lowa@bxbb.com", "name": "lowa"}    | "lowa"    |
|   3 | {"age": 99, "name": "lm", "email": "limin@bxbb.com"}    | "lm"      |
+-----+---------------------------------------------------------+-----------+
3 rows in set (0.00 sec)

3.添加索引
mysql> alter table test_json add index idx(user_name);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

4.查看执行计划
mysql> explain select * from test_json where user_name='"lowa"'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_json
   partitions: NULL
         type: ref
possible_keys: idx
          key: idx
      key_len: 131
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

mysql> show create table test_json\G
*************************** 1. row ***************************
       Table: test_json
Create Table: CREATE TABLE `test_json` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `data` json DEFAULT NULL,
  `user_name` varchar(32) GENERATED ALWAYS AS (json_extract(`data`,'$.name')) VIRTUAL,
  PRIMARY KEY (`uid`),
  KEY `idx` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

七、字符集相关

1. MySQL字符集包括:

字符集(character) --用于定义字符串的存储方式 校对规则(collation) --用于定义比较字符串的方式 常用的字符集:

  • utf8:最常用的字符集,占3个字节
  • utf8mb4:utf8的超级,占4个字节
  • gbk : 占2个字节,通用性没有utf8好
  • gb18030: 是最新的汉字编码字符集国家标准, 向下兼容 GBK 和 GB2312 标准,编码是一二四字节变长编码
mysql> show character set;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese        | big5_chinese_ci     |      2 |
| dec8     | DEC West European               | dec8_swedish_ci     |      1 |
| cp850    | DOS West European               | cp850_general_ci    |      1 |
| hp8      | HP West European                | hp8_english_ci      |      1 |
| koi8r    | KOI8-R Relcom Russian           | koi8r_general_ci    |      1 |
| latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |
| latin2   | ISO 8859-2 Central European     | latin2_general_ci   |      1 |
| swe7     | 7bit Swedish                    | swe7_swedish_ci     |      1 |
| ascii    | US ASCII                        | ascii_general_ci    |      1 |
| ujis     | EUC-JP Japanese                 | ujis_japanese_ci    |      3 |
| sjis     | Shift-JIS Japanese              | sjis_japanese_ci    |      2 |
| hebrew   | ISO 8859-8 Hebrew               | hebrew_general_ci   |      1 |
| tis620   | TIS620 Thai                     | tis620_thai_ci      |      1 |
| euckr    | EUC-KR Korean                   | euckr_korean_ci     |      2 |
| koi8u    | KOI8-U Ukrainian                | koi8u_general_ci    |      1 |
| gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
| greek    | ISO 8859-7 Greek                | greek_general_ci    |      1 |
| cp1250   | Windows Central European        | cp1250_general_ci   |      1 |
| gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
| latin5   | ISO 8859-9 Turkish              | latin5_turkish_ci   |      1 |
| armscii8 | ARMSCII-8 Armenian              | armscii8_general_ci |      1 |
| utf8     | UTF-8 Unicode                   | utf8_general_ci     |      3 |
| ucs2     | UCS-2 Unicode                   | ucs2_general_ci     |      2 |
| cp866    | DOS Russian                     | cp866_general_ci    |      1 |
| keybcs2  | DOS Kamenicky Czech-Slovak      | keybcs2_general_ci  |      1 |
| macce    | Mac Central European            | macce_general_ci    |      1 |
| macroman | Mac West European               | macroman_general_ci |      1 |
| cp852    | DOS Central European            | cp852_general_ci    |      1 |
| latin7   | ISO 8859-13 Baltic              | latin7_general_ci   |      1 |
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_general_ci  |      4 |
| cp1251   | Windows Cyrillic                | cp1251_general_ci   |      1 |
| utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |
| utf16le  | UTF-16LE Unicode                | utf16le_general_ci  |      4 |
| cp1256   | Windows Arabic                  | cp1256_general_ci   |      1 |
| cp1257   | Windows Baltic                  | cp1257_general_ci   |      1 |
| utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |
| binary   | Binary pseudo charset           | binary              |      1 |
| geostd8  | GEOSTD8 Georgian                | geostd8_general_ci  |      1 |
| cp932    | SJIS for Windows Japanese       | cp932_japanese_ci   |      2 |
| eucjpms  | UJIS for Windows Japanese       | eucjpms_japanese_ci |      3 |
| gb18030  | China National Standard GB18030 | gb18030_chinese_ci  |      4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.00 sec)

2. collation(排序规则)

collation的含义是指排序规则, ci(case insensitive) 结尾的排序集是不区分大小写的

mysql> select 'a' = 'A';
+-----------+
| 'a' = 'A' |
+-----------+
|         1 |
+-----------+
1 row in set (0.00 sec)

mysql> create table test_ci (a varchar(10), key(a));
Query OK, 0 rows affected (0.03 sec)

mysql> insert into test_ci values('a');
Query OK, 1 row affected (0.01 sec)

mysql> insert into test_ci values('A');
Query OK, 1 row affected (0.01 sec)

mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

是不是感觉很神奇!!!a=A 居然是TRUE! 解释一下为什么会出现以上的情况。 首先,查下默认的排序规则

mysql> show variables like '%coll%';
+----------------------+--------------------+
| Variable_name        | Value              |
+----------------------+--------------------+
| collation_connection | utf8_general_ci    |
| collation_database   | utf8mb4_general_ci |
| collation_server     | utf8mb4_general_ci |
+----------------------+--------------------+
3 rows in set (0.00 sec)

ci(case insensitive) 结尾的排序集是不区分大小写的,所以才有了以上的结果

 // 修改当前session的collate,a终于不等于A 了,但是表里面的数据还是 a=A
 mysql> set names utf8mb4 collate utf8mb4_bin;
Query OK, 0 rows affected (0.00 sec)

mysql> select 'a' = 'A';
+-----------+
| 'a' = 'A' |
+-----------+
|         0 |
+-----------+
1 row in set (0.00 sec)

mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

//修改了session的collate对表数据不起作用,因为表自身也有collate。
//尝试给表修改collate
mysql> alter table test_ci collate utf8mb4_bin;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

//发现还是a=A,这是因为只修改collate,对已经存在的数据不起作用
mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
| A    |
+------+
2 rows in set (0.00 sec)

// 要使得已经存在的数据也修改新的collate,需要用convert命令进行转换
mysql> alter table test_ci convert to character set utf8mb4 collate utf8mb4_bin;
Query OK, 2 rows affected (0.07 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from test_ci where a = 'a';
+------+
| a    |
+------+
| a    |
+------+
1 row in set (0.00 sec)

mysql>

//另外,如果没有数据,可以直接用下面的sql进行修改
mysql> alter table test_ci character set utf8mb4 collate utf8mb4_bin;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

3. 乱码问题

字符集涉及的范围很广,像程序链接、数据库、服务器、表以及表中的字段、结果集,都会涉及到字符集。字符集最容易遇到的问题就是乱码。

 mysql> show variables like '%char%';
+--------------------------+----------------------------------------------------------------+
| Variable_name            | Value                                                          |
+--------------------------+----------------------------------------------------------------+
| character_set_client     | utf8                                                           |
| character_set_connection | utf8                                                           |
| character_set_database   | utf8mb4                                                        |
| character_set_filesystem | binary                                                         |
| character_set_results    | utf8                                                           |
| character_set_server     | utf8mb4                                                        |
| character_set_system     | utf8                                                           |
| character_sets_dir       | /usr/local/mysql-5.7.22-linux-glibc2.12-x86_64/share/charsets/ |
+--------------------------+----------------------------------------------------------------+
8 rows in set (0.00 sec)

如何解决乱码呢? 答案是:保证三者一致。 三者包括:连接终端的字符集、操作系统的字符集、MySQL数据库的字符集。 如果想要临时的修改数据库字符集,可以在数据库命令行执行set names xxx来实现。 三者统一都是UTF8,就不会出现中文乱码的情况了。

Copyright © suredandan 2018 all right reserved,powered by GitbookUpdateTime: 2020-04-09 16:35:45

results matching ""

    No results matching ""