数据类型和运算符
1 . MySQL数据类型介绍
MySQL主要支持的数据类型有:数值类型、日期/时间类型、字符串类型。
(1)数值数据类型:包括整数类型TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT、浮点小数数据类型FLOAT和DOUBLE、定点小数类型DECIMAL。
(2)日期/时间类型:包括YEAR、TIME、DATE、DATETIME和TIMESTAMP。
(3)字符串类型:包括CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET等。
1.1 整数类型
整数类型的属性字段可以添加AUTO_INCREMENT自增约束条件。
MySQL中的整数型数据类型:
类型名称 | 说明 | 存储需求 |
---|---|---|
TINYINT | 很小的整数 | 1个字节(8 bits) |
SMALLINT | 小的整数 | 2个字节 |
MEDIUMINT | 中等大小的整数 | 3个字节 |
INT(INTEGER)INT | 普通大小的整数 | 4个字节 |
BIGINT | 大整数 | 8个字节 |
不同整数类型的取值范围
数据类型 | 有符号 | 无符号 |
---|---|---|
TINYINT | -128~127 | 0~255 |
SMALLINT | -32768~32767 | 0~65535 |
MEDIUMINT | -8388608~8388607 | 0~16777215 |
INT(INTEGER)INT | -2147483648~2147482617 | 0~4294967295 |
BIGINT | -9223372036854775808~9223372036854775807 | 0~18446744073709551615 |
下面你需要注意的地方是:如INT(11)里的111表示的是该数据类型指定的显示宽度。显示宽度和数据类型的取值范围是无关的 。显示宽度只是指明MySQL最大可能显示的数字个数,数值的位数小于指定的宽度时会由空格填充;如果插入大于显示宽度的值,只要该值不超过该类型整数的取值范围,数值一样可以插入并能够显示出来。
例:创建表rmp1,其中字段x、y、z、m、n数据类型依次为TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,SQL语句如下:
mysql> CREATE TABLE rmp1(x TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT);
Query OK, 0 rows affected (2.13 sec)
查看表结构:
mysql> DESC rmp1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| x | tinyint(4) | YES | | NULL | |
| y | smallint(6) | YES | | NULL | |
| z | mediumint(9) | YES | | NULL | |
| m | int(11) | YES | | NULL | |
| n | bigint(20) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.19 sec)
可以看到系统给每一个字段添加不同的默认使用宽度。
注:显示宽度只用于显示,并不能限制取值范围和占用空间,如:INT(3)会占用4个字节的存储空间,但是允许的最大值是INT允许的最大值。
1.2浮点数类型和定点数类型
浮点类型有两种:单精度浮点数类型(FLOAT)和双精度浮点类型(DOUBLE)。
定点类型:DECIMAL。
这两种类型均可以使用(M,N)表示,M(精度)表示总共的位数;N(标度)表示小数的位数。
MySQL中的小数类型
类型名称 | 说明 | 存储需求 |
---|---|---|
FLOAT | 单精度浮点数 | 4个字节 |
DOUBLE | 双精度浮点数 | 8个字节 |
DECIMAL (M,D) DEC | 压缩的“严格”定点数 | M+2个字节 |
数据类型 | 有符号 | 无符号 |
---|---|---|
FLOAT | -3.402823466E+38~-1.175494351E-38 | 0和1.175494351E-38~3.402823466E+38 |
DOUBLE | -1.7976931348623157E+308~-2.2250738585072014E-308 | 0和2.2250738585072014E-308~1.7976931348623157E+308 |
提示:如果用户指定的精度超出精度范围,则会四舍五入进行处理。
例:创建表tmp2,其中字段x、y、z数据类型依次为FLOAT(5,1)、DOUBLE(5,1)和DECIMAL(5,1),向表中插入数据5.12,5.15和5.123,SQL语句如下:
mysql> CREATE TABLE tmp2(x FLOAT(5,1), y DOUBLE(5,1), z DECIMAL(5,1));
Query OK, 0 rows affected (0.62 sec)
mysql> INSERT INTO tmp2 VALUES(5.12,5.15,5.123);
Query OK, 1 row affected, 1 warning (0.22 sec)
mysql> SHOW WARNINGS;
+-------+------+----------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------+
| Note | 1265 | Data truncated for column 'z' at row 1 |
+-------+------+----------------------------------------+
1 row in set (0.14 sec)
可以看到FLOAT和DOUBLE在进行四舍五入时没有给出警告,但给出了z字段数值被截断警告。
查看结果:
mysql> SELECT * FROM tmp2;
+------+------+------+
| x | y | z |
+------+------+------+
| 5.1 | 5.2 | 5.1 |
+------+------+------+
1 row in set (0.18 sec)
FLOAT和DOUBLE在不指定精度时,默认会按照实际的精度,而DECIMAL在不指定精度时会默认(10,0)。
注:浮点数能表示更大的数据范围,但会引起精度问题。
1.3日期与时间类型
MySQL中表示日期的数据类型:DATETIME、DATETIME、STAMP、TIME和YEAR。
类型名称 | 日期格式 | 日期范围 | 存储需求 |
---|---|---|---|
YEAR | YYYY | 1901~2155 | 1字节 |
TIME | HH:MM:SS | -838:59:59~838:59:59 | 3字节 |
DATE | YYYY-MM-DD | 1000-01-01~9999-12-31 | 3字节 |
DATETIME | YYYY-MM-DD HH-MM-SS | 1000-01-01 00:00:00~9999-12-31 23:59:59 | 8字节 |
TIMESTAMP | YYYY-MM-DD HH:MM:SS | 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC | 4字节 |
1.year
可以使用下列格式指定YEAR的值:
- 以4位字符串或数字表示,即’YYYY’或者YYYY,范围:‘1901’~‘2155’.
- 以2位字符串格式表示, ‘00’ ~ ‘69’ 和 ‘70’ ~ '99’范围的值分别被转换为2000~ 2069和1970~ 1999范围的YEAR值。'0’与’00’的作用相同,若插入超过取值范围的值将被转换为2000。
- 以2位数字表示与以字符串格式表示类似。注意:这里0值会被转换成0000.
例:创建表tmp3,定义数据类型为YEAR的字段y,向表中插入值为2010,‘2010’,‘2166’,SQL语句如下:
mysql> CREATE TABLE tmp3(y YEAR);
Query OK, 0 rows affected (1.78 sec)
mysql> INSERT INTO tmp3 values(2010),('2010'),('2166');
ERROR 1264 (22003): Out of range value for column 'y' at row 3
出现错误,超出范围。(这里与上面笔记所说不相符,大概是MySQL版本的问题)
例:向tmp3表中y字段插入2位字符串表示的YEAR值,分别为‘0’、‘00’、‘77’和‘10’,语句如下:
首先删除表中数据
mysql> DELETE FROM tmp3;
Query OK, 0 rows affected (0.14 sec)
向表中插入数据
mysql> INSERT INTO tmp3 values('0'),('00'),('77'),('10');
Query OK, 4 rows affected (0.10 sec)
Records: 4 Duplicates: 0 Warnings: 0
查看结果
mysql> SELECT * FROM tmp3;
+------+
| y |
+------+
| 2000 |
| 2000 |
| 1977 |
| 2010 |
+------+
4 rows in set (0.02 sec)
其他就不一 一展示。
2.TIME
格式:
- ‘D HH:MM:SS’/‘HH:MM:SS’/‘D HH:MM’/‘D HH’/‘SS’。这里D表示日(0~34),在插入数据库时,D被转换为小时保存,格式为“D*24+HH”。
- ‘HHMMSS’。
例:创建数据表tmp4,定义数据类型为TIME字段t,向表中插入值’10:05:05’,‘23:23’,‘2 10:10’,‘3 02’,‘10’,SQL语句如下:
mysql> CREATE TABLE tmp4(t TIME);
Query OK, 0 rows affected (0.56 sec)
mysql> INSERT INTO tmp4 VALUES('10:05:05'),('23:23'),('2 10:10'),('3 02'),('10');
Query OK, 5 rows affected (0.14 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp4;
+----------+
| t |
+----------+
| 10:05:05 |
| 23:23:00 |
| 58:10:00 |
| 74:00:00 |
| 00:00:10 |
+----------+
5 rows in set (0.12 sec)
注:在使用D HH格式时,小时一定要使用双位数。
例:向表tmp4中插入值’101112’,111213,‘0’,107010,SQL语句如下:
首先删除数据:
mysql> DELETE FROM tmp4;
Query OK, 5 rows affected (0.18 sec)
向表中插入数据:
mysql> INSERT INTO tmp4 VALUES('10112'),(111213),('0'),(107010);
ERROR 1292 (22007): Incorrect time value: '107010' for column 't' at row 4
可以看到有错误产生,即在插入第4条数据时,数据超出了范围,原因是70超出了60分钟。
下面使用系统日期函数向TIME字段插入值。
例:向tmp4插入系统当前时间,SQL语句如下:
mysql> INSERT INTO tmp4 VALUES(CURRENT_TIME),(NOW());
Query OK, 2 rows affected (0.18 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp4;
+----------+
| t |
+----------+
| 08:43:00 |
| 08:43:00 |
+----------+
2 rows in set (0.00 sec)
1.3DATE类型(3bytes)
-
‘YYYY-MM-DD’ or 'YYYYMMDD’字符格式表示日期,取值范围:
‘1000-0101’~ ‘9999-12-3’ 。 -
‘YY-MM-DD’~ 'YYMMDD’字符格式表示日期
'00~ 69’表示‘2000 ~ 2069’
'70~99’表示‘1970 ~1999’。 -
YY-MM-DD or YYMMDD数字格式表示日期,范围与2相似,但是YY-MM-DD需要用双引号引上。
例:创建数据表tmp5,定义数据类型为DATE的字段d,向表中插入“YYYY-MM-DD”和“YYYYMMDD”字符串格式日期,SQL语句如下:
mysql> CREATE TABLE tmp5(d DATE);
Query OK, 0 rows affected (0.53 sec)
mysql> INSERT INTO tmp5 VALUES('1998-08-08'),('19980808'),('20101010');
Query OK, 3 rows affected (0.06 sec)
查看结果:
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 1998-08-08 |
| 1998-08-08 |
| 2010-10-10 |
+------------+
3 rows in set (0.00 sec)
例:向tmp5表中插入“YY-MM-DD”和“YYMMDD”字符串格式日期,SQL 语句如下:
mysql> DELETE FROM tmp5;
Query OK, 3 rows affected (0.06 sec)
mysql> INSERT INTO tmp5 VALUES('99-09-09'),('990909'),('000101'),('111111');
Query OK, 4 rows affected (0.11 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 1999-09-09 |
| 1999-09-09 |
| 2000-01-01 |
| 2011-11-11 |
+------------+
4 rows in set (0.00 sec)
例:向tmp5表中插入YY-MM-DD和YYMMDD数字格式日期,SQL语句如下:
mysql> INSERT INTO tmp5 VALUES("990909"),(990909),(000101),(111111);
Query OK, 4 rows affected (0.11 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 1999-09-09 |
| 1999-09-09 |
| 2000-01-01 |
| 2011-11-11 |
+------------+
4 rows in set (0.00 sec)
例:向tmp5插入系统当前日期:
mysql> DELETE FROM tmp5;
Query OK, 4 rows affected (0.08 sec)
mysql> INSERT INTO tmp5 VALUES(CURRENT_DATE()),(NOW());
Query OK, 2 rows affected, 1 warning (0.06 sec)
Records: 2 Duplicates: 0 Warnings: 1
mysql> SELECT * FROM tmp5;
+------------+
| d |
+------------+
| 2018-11-30 |
| 2018-11-30 |
+------------+
2 rows in set (0.00 sec)
CURRENT_DATE()只返回当前日期值
NOW()返回日期和时间值,这里d为DATE类型,故只保存了DATE部分
提示:MySQL允许不严格的语法:任何标点符号都可以用作日期部分之间的间隔符。
1.4DATETIME
格式:
- ‘YYYY-MM-DD HH:MM:SS’、‘YYYYMMDDHHMMSS’字符串格式表示,取值范围‘1000-01-01 00:00:00’~‘9999-12-3 23:59:59’。
- ‘YY-MM-DD HH:MM:SS’、‘YYMMDDHHMMSS’字符串格式表示,取值范围YY表示年值,其取值范围与前面日期的相同。
- YYYYMMDDHHMMSS、YYMMDDHHMMSS数字格式表示。
例:创建数据表tmp6,定义数据类型为DATETIME的字段dt,向表中插入日期和时间值(这里只演示数字格式和插入系统当前日期和时间值)
创建数据表:
mysql> CREATE TABLE tmp6(dt DATETIME);
Query OK, 0 rows affected (0.46 sec)
插入值:
mysql> INSERT INTO tmp6 VALUES(19970823121314),(NOW());
Query OK, 2 rows affected (0.13 sec)
Records: 2 Duplicates: 0 Warnings: 0
查看值:
mysql> SELECT * FROM tmp6;
+---------------------+
| dt |
+---------------------+
| 1997-08-23 12:13:14 |
| 2018-11-30 14:36:34 |
+---------------------+
2 rows in set (0.07 sec)
MySQL允许不严格的语法,实验:
1
mysql> INSERT INTO tmp6 VALUES('2018$06&18 08\18+50');
ERROR 1292 (22007): Incorrect datetime value: '2018$06&18 0818+50' for column 'dt' at row 1
2
mysql> INSERT INTO tmp6 VALUES('2018$06&18 08/18?50');
Query OK, 1 row affected (0.14 sec)
3
mysql> INSERT INTO tmp6 VALUES('2018$06&18 08\18\15');
ERROR 1292 (22007): Incorrect datetime value: '2018$06&18 081815' for column 'dt' at row
只有第2个可以插入。
5.TIMESTAMP
TIMESTAMP显示格式与DATETIME相同,日期格式为:YYYY-MM-DD HH:MM:SS。但取值范围比DATETIME小,其取值范围为:‘1970-01-01 00:00:01’ UTC ~ ‘2038-01-19 03:14:07’ UTC,UTC:世界标准时间。
例:创建数据表tmp7,向表中插入值:
mysql> CREATE TABLE tmp7(ts TIMESTAMP);
Query OK, 0 rows affected (0.38 sec)
mysql> INSERT INTO tmp7 VALUES('97@12@12 12@12@12'),(NOW());
Query OK, 2 rows affected (0.15 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp7;
+---------------------+
| ts |
+---------------------+
| 1997-12-12 12:12:12 |
| 2018-11-30 14:52:11 |
+---------------------+
2 rows in set (0.00 sec)
TIMESTAMP存储的时间与当前所处的时区有关。
例:向tmp7表中插入当前日期,查看插入值,将时区改为东10区,再次查看插入值:
mysql> DELETE FROM tmp7;
Query OK, 2 rows affected (0.13 sec)
mysql> INSERT INTO tmp7 VALUES(NOW());
Query OK, 1 row affected (0.06 sec)
mysql> SELECT * FROM tmp7;
+---------------------+
| ts |
+---------------------+
| 2018-11-30 14:55:07 |
+---------------------+
1 row in set (0.00 sec)
mysql> set time_zone='+10:00';
Query OK, 0 rows affected (0.06 sec)
mysql> SELECT * FROM tmp7;
+---------------------+
| ts |
+---------------------+
| 2018-11-30 16:55:07 |
+---------------------+
1 row in set (0.00 sec)
1.5字符串类型
MySQL中的字符串类型:
类型名称 | 说明 | 存储需求 |
---|---|---|
CHAR(M) | 固定长度非二进制字符串 | M字节,1<=M<=255 |
VARCHAR(M) | 变长非二进制字符串 | L+1字节,L<=M,1<=M<=255 |
TINYTEXT | 非常小的非二进制字符串 | L+1字节,L<2^8 |
TEXT | 小的非二进制字符串 | L+2字节,L<2^16 |
MEDIUMTEXT | 中等大小的非二进制字符串 | L+3字节,L<2^24 |
LONGTEXT | 大的非二进制字符串 | L+4字节,L<2^32 |
ENUM | 枚举类型,只能有一个枚举字符串值 | 1或2个字节,取决于枚举值的数目(最大值65535) |
SET | 一个设置,字符串对象可以有0个或多个SET成员 | 1,2,3,4或8个字节,取决于集合成员的数量(最多64个成员) |
1.CHAR与VARCHAR
CHAR固定长度,当检索到CHAR值时,尾部的空格将被删除掉,且无论存入的长度为多少,所占的空间均为定义时指定的字符串列长。
VARCHAR在值保存和检索时尾部的空格仍保留,且其定义的列所占的字节数为实际长度加1。
例:创建tmp8表,定义字段ch(CHAR(4)),vch(VARCHAR(4))向表中插入数据“ab ”,SQL语句如下:
mysql> CREATE TABLE tmp8(
-> ch CHAR(4),
-> vch VARCHAR(4)
-> );
Query OK, 0 rows affected (1.51 sec)
mysql> INSERT INTO tmp8 VALUES('ab ','ab ')
-> ;
Query OK, 1 row affected (0.16 sec)
查询结果:
mysql> SELECT concat('(',ch,')'),concat('(',vch,')') FROM tmp8;
+--------------------+---------------------+
| concat('(',ch,')') | concat('(',vch,')') |
+--------------------+---------------------+
| (ab) | (ab ) |
+--------------------+---------------------+
1 row in set (0.21 sec)
可以看到,ch在保存值时把尾部空格删去,而vch仍保留尾部空格。
2.TEXT类型
TEXT列保存非二进制字符串,如文章内容、评论等。
Text类型有四种:TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT。
3.ENUM类型
ENUM是一个字符串对象,其值为表创建时在列规定中枚举的一列值。
语法格式:字段名 ENUM('值 1' , '值 2' , ... , '值 n')
每个枚举值均有一个索引值,但是请注意存储值不是一个十分明智的选择,故一般存储索引。
ENUM类型的取值范围:
值 | 索引 |
---|---|
NULL | NULL |
‘’ | 0 |
first | 1 |
second | 2 |
third | 3 |
例:创建表tmp9,定义ENUM类型的列enm(‘first’ , ‘second’ , ‘third’),查看列成员的索引值:
mysql> CREATE TABLE tmp9(enm ENUM('first','second','third'));
Query OK, 0 rows affected (0.54 sec)
mysql> INSERT INTO tmp9 values('first'),('second'),('third'),(NULL);
Query OK, 4 rows affected (0.15 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT enm ,enm+0 FROM tmp9;
+--------+-------+
| enm | enm+0 |
+--------+-------+
| first | 1 |
| second | 2 |
| third | 3 |
| NULL | NULL |
+--------+-------+
4 rows in set (0.54 sec)
我试了一下,发现我mysql版本无法输入‘’,我想应该是需要更高的版本吧!
4.set类型
例:创建表tmp11,定义set类型字段,取值列表为(‘a’,‘b’,‘c’,‘d’),插入数据(‘a’),(‘a,b,a’),(‘c,a,d’),(‘a,x,b,y’),SQL语句如下:
mysql> CREATE TABLE tmp11(s SET('a','b','c','d'));
Query OK, 0 rows affected (0.37 sec)
mysql> INSERT INTO tmp11 VALUES('a'),('a,b,a'),('c,a,b'),('a,x,b,y');
ERROR 1265 (01000): Data truncated for column 's' at row 4
可以看到由于插入了SET列不支持的类型,出现错误。
重新插入
mysql> INSERT INTO tmp11 VALUES('a'),('a,b,a'),('c,a,b');
Query OK, 3 rows affected (0.04 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tmp11;
+-------+
| s |
+-------+
| a |
| a,b |
| a,b,c |
+-------+
3 rows in set (0.00 sec)
从结果可以看出,set不允许重复,且有先后顺序明确。
1.5 二进制类型
MySQL支持两类字符型数据:文本字符串、二进制字符串。
二进制数据类型有:BIT、BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBOLB、LONGBLOB。
1.BIT类型
BIT数据类型用来保存位字段值,BIT(M),M表示每个值的位数,范围1~64。若M被忽略,默认1。
例:创建表tmp12,定义BIT(4)类型的字段b,向表中插入数据2、9、15、16。
mysql> INSERT INTO tmp12 VALUES(2),(9),(15),(16);
ERROR 1406 (22001): Data too long for column 'b' at row 4
出现错误,16超出了4位二进制数的范围。
mysql> SELECT BIN(b+0) FROM tmp12;
+----------+
| BIN(b+0) |
+----------+
| 10 |
| 1001 |
| 1111 |
+----------+
3 rows in set (0.09 sec)
mysql> SELECT b+0 FROM tmp12;
+------+
| b+0 |
+------+
| 2 |
| 9 |
| 15 |
+------+
3 rows in set (0.00 sec)
其中: b+0表示将二进制的结果转换为对应的数字值,BIN()函数将数字转化为二进制。
2.BINARY和VARBINARY
BINARY和VARBINARY类似于CHAER和VARCHAR,BINARY类型的长度是固定的,VARBINARY类型的长度是可变的且实际占用空间为字符串实际长度加一。
例:创建表tmp13,定义BINARY(3)类型字段b和VARBINARY(3)类型的字段vb,并向表中插入数据‘5’,比较两个字段的存储空间:
mysql> CREATE TABLE tmp13(b BINARY(3),vb VARBINARY(3));
Query OK, 0 rows affected (0.34 sec)
mysql> INSERT INTO tmp13 VALUES(5,5);
Query OK, 1 row affected (0.02 sec)
mysql> SELECT length(b),length(vb) FROM tmp13;
+-----------+------------+
| length(b) | length(vb) |
+-----------+------------+
| 3 | 1 |
+-----------+------------+
1 row in set (0.00 sec)
进一步确认5在两个字段中不同的存储方式:
mysql> SELECT b,vb,b='5',b='5\0\0',vb='5',vb='5\0\0' FROM tmp13;
+------+------+-------+-----------+--------+------------+
| b | vb | b='5' | b='5\0\0' | vb='5' | vb='5\0\0' |
+------+------+-------+-----------+--------+------------+
| 5 | 5 | 0 | 1 | 1 | 0 |
+------+------+-------+-----------+--------+------------+
1 row in set (0.00 sec)
b字段不足的空间填充了‘\0’。
3.BOLB类型
BLOB类型的存储范围:
数据类型 | 存储范围 |
---|---|
TINYBLOB | 最大长度为255(28-1)字节 |
BLOB | 最大长度为65535(216-1)字节 |
MEDIUMBLOB | 最大长度为16777215(224-1)字节 |
LONGBLOB | 最大长度为4294967295或4GB(232-1)字节 |
BLOB列存储的是二进制字符串(字节字符串);TEXT列存储的是字符字符串。BLOB列没有字符集,并且排序和比较基于列字节的数值;TEXT列有一个字符集,并且根据字符集对值进行排序和比较。