本文翻译自官方文档。
MySQL支持以下几种SQL数据类型:
本章提供了对每个类别中类型的属性的概述和更详细的描述,数据类型描述使用以下约定:
TIME
、DATETIME
和TIMESTAMP
类型,表示小数秒精度,即秒的小数部分的小数点后面的位数。如果给定fsp值,则必须在0到6的范围内。值为0表示没有小数部分。如果省略,默认精度为0。MySQL支持所有标准的SQL数字数据类型。这些类型包括精确数字数据类型(INTEGER
、SMALLINT
、DECIMAL
和NUMERIC
),以及近似数字数据类型(FLOAT
、REAL
和DOUBLE
PRECISION
)。关键字INT
是INTEGER
的同义词,关键字DEC
和FIXED
是DECIMAL
的同义词。MySQL将DOUBLE
视为DOUBLE PRECISION
(一个非标准扩展)的同义词。MySQL也将REAL
视为DOUBLE PRECISION
的同义词,除非启用了REAL_AS_FLOAT
SQL模式。BIT
数据类型存储位值,支持MyISAM、MEMORY、InnoDB和NDB表。
对于整数数据类型,M表示最小显示宽度。最大显示宽度为255。显示宽度与类型可以存储的值范围无关。对于浮点和定点数据类型,M是可以存储的总位数。整数数据类型允许UNSIGNED
属性和SIGNED
属性,其中SIGNED
属性是默认的。
BIT[(M)]
用于存储位值。M表示每个值的位数,取值范围为1 ~ 64。如果省略M,则默认为1。TINYINT[(M)] [UNSIGNED]
:一个非常小的整数。取值范围为-128 ~ 127。无符号范围是0到255。BOOL, BOOLEAN
:这些类型是TINYINT(1)
的同义词。值为零被认为是false
。非零值被认为是true
:mysql> SELECT IF(0, 'true', 'false');
+------------------------+
| IF(0, 'true', 'false') |
+------------------------+
| false |
+------------------------+
mysql> SELECT IF(1, 'true', 'false');
+------------------------+
| IF(1, 'true', 'false') |
+------------------------+
| true |
+------------------------+
mysql> SELECT IF(2, 'true', 'false');
+------------------------+
| IF(2, 'true', 'false') |
+------------------------+
| true |
+------------------------+
然而,值TRUE
和FALSE
分别只是1和0的别名,如下所示:
mysql> SELECT IF(0 = FALSE, 'true', 'false');
+--------------------------------+
| IF(0 = FALSE, 'true', 'false') |
+--------------------------------+
| true |
+--------------------------------+
mysql> SELECT IF(1 = TRUE, 'true', 'false');
+-------------------------------+
| IF(1 = TRUE, 'true', 'false') |
+-------------------------------+
| true |
+-------------------------------+
mysql> SELECT IF(2 = TRUE, 'true', 'false');
+-------------------------------+
| IF(2 = TRUE, 'true', 'false') |
+-------------------------------+
| false |
+-------------------------------+
mysql> SELECT IF(2 = FALSE, 'true', 'false');
+--------------------------------+
| IF(2 = FALSE, 'true', 'false') |
+--------------------------------+
| false |
+--------------------------------+
SMALLINT[(M)] [UNSIGNED]
:一个小整数。带符号的范围是-32768到32767。无符号取值范围是0 ~ 65535。MEDIUMINT[(M)] [UNSIGNED]
:中等大小的整数。带符号的范围是-8388608 ~ 8388607。无符号范围是0到16777215。INT[(M)] [UNSIGNED]
:正常大小的整数。带符号的范围是-2147483648 ~ 2147483647。无符号范围是0 ~ 4294967295。BIGINT[(M)] [UNSIGNED]
:大整数。符号范围为-9223372036854775808 ~ 9223372036854775807。无符号取值范围是0 ~ 18446744073709551615。DECIMAL[(M[,D])]
:一个紧凑的精确定点数字。FLOAT
:单精度浮点数,MySQL为单精度值使用4个字节,取值范围为-3.402823466E+38 ~ - 1.175494351e - 38
、0
和1.175494351E-38 ~ 3.402823466E+38
。DOUBLE
:双精度浮点数,MySQL为双精度值使用8个字节。取值范围为-1.7976931348623157E+308 ~ - 2.2250738585072014e - 308,0和2.2250738585072014E-308 ~ 1.7976931348623157E+308。MySQL中所有算术都是使用有符号的BIGINT
或DOUBLE
值完成。
数字字面值包括精确值(整数和DECIMAL
)字面量和近似值(浮点)字面量。
.
作为小数分隔符。数字前面可以加-
或+
,分别表示负值或正值。用尾数和指数表示的科学记数法中的数字是近似值数字。两个看起来相似的数字可能会被区别对待。例如,2.34是一个精确值,而2.34E0是一个近似值。
十六进制文字值使用X'val'
表示法写入,其中val
包含十六进制数字。数字和任何前导X
的字母大小写不重要。
X'01AF'
X'01af'
x'01AF'
x'01af'
使用X'val'
表示法写入的值必须包含偶数位,否则会出现语法错误。要纠正这个问题,在值中填充一个前导零。
默认情况下,十六进制字面值是一个二进制字符串,其中每对十六进制数字代表一个字符。
mysql> SELECT X'4D7953514C', CHARSET(X'4D7953514C');
+---------------+------------------------+
| X'4D7953514C' | CHARSET(X'4D7953514C') |
+---------------+------------------------+
| MySQL | binary |
+---------------+------------------------+
十六进制字面值可以有一个可选的字符集引入器和COLLATE
子句,将其指定为使用特定字符集和排序规则的字符串:
[_charset_name] X'val' [COLLATE collation_name]
在数字上下文中,MySQL将十六进制字面值视为BIGINT UNSIGNED
(64位无符号整数)。要确保十六进制字面值的数字处理,请在数字上下文中使用它。实现此目的的方法包括添加0
或使用CAST(… AS UNSIGNED)
。
mysql> SET @v1 = X'41';
mysql> SET @v2 = X'41'+0;
mysql> SET @v3 = CAST(X'41' AS UNSIGNED);
mysql> SELECT @v1, @v2, @v3;
+------+------+------+
| @v1 | @v2 | @v3 |
+------+------+------+
| A | 65 | 65 |
+------+------+------+
空的十六进制值X' '
计算为零长度的二进制字符串。转换成数字后,结果为0
:
mysql> SELECT CHARSET(X''), LENGTH(X'');
+--------------+-------------+
| CHARSET(X'') | LENGTH(X'') |
+--------------+-------------+
| binary | 0 |
+--------------+-------------+
mysql> SELECT X''+0;
+-------+
| X''+0 |
+-------+
| 0 |
+-------+
位值文字使用b'val'
表示法书写。Val是一个用0和1写成的二进制值。以字母b开头的字母不重要。
b'01'
B'01'
默认情况下,位值字面值是一个二进制字符串:
mysql> SELECT b'1000001', CHARSET(b'1000001');
+------------+---------------------+
| b'1000001' | CHARSET(b'1000001') |
+------------+---------------------+
| A | binary |
+------------+---------------------+
位值字面值可以有一个可选的字符集引入器和COLLATE子句,将其指定为使用特定字符集和排序规则的字符串:
[_charset_name] b'val' [COLLATE collation_name]
在数字上下文中,MySQL将位字面值视为整数。要确保位字面值的数字处理,请在数字上下文中使用它。实现此目的的方法包括添加0
或使用CAST(…unsigned)
。
mysql> SET @v1 = b'1100001';
mysql> SET @v2 = b'1100001'+0;
mysql> SET @v3 = CAST(b'1100001' AS UNSIGNED);
mysql> SELECT @v1, @v2, @v3;
+------+------+------+
| @v1 | @v2 | @v3 |
+------+------+------+
| a | 97 | 97 |
+------+------+------+
对于位字面值,位操作被认为是数字上下文,但在MySQL 8.0及更高版本中,位操作允许数字或二进制字符串参数。要显式地为位字面值指定二进制字符串上下文,请为至少一个参数使用_binary
引入器:
mysql> SET @v1 = b'000010101' | b'000101010';
mysql> SET @v2 = _binary b'000010101' | _binary b'000101010';
mysql> SELECT HEX(@v1), HEX(@v2);
+----------+----------+
| HEX(@v1) | HEX(@v2) |
+----------+----------+
| 3F | 003F |
+----------+----------+
对于这两个位操作,显示的结果看起来很相似,但是没有_binary
的结果是一个BIGINT
值,而有_binary
的结果是一个二进制字符串。由于结果类型不同,因此显示的值不同:数值结果不显示高阶0。
常量TRUE
和FALSE
的值分别为1和0。常数名可以用任何字母形式书写。
mysql> SELECT TRUE, true, FALSE, false;
-> 1, 1, 0, 0
MySQL支持一个扩展,可以在类型的基本关键字后面的括号中选择性地指定整数数据类型的显示宽度。例如,INT(4)
指定一个显示宽度为四位数的INT
。
显示宽度不约束可存储在列中的值的范围。它也不会阻止比列显示宽度宽的值被正确显示。例如,指定为SMALLINT(3)
的列具有通常的SMALLINT
范围-32768到32767,并且三位数允许的范围之外的值将使用三个以上的数字完整显示。
所有的整数类型都可以有一个可选的UNSIGNED
属性。无符号类型可用于仅允许在列中使用非负数,或者当需要为列设置更大的上数值范围时。例如,如果一个INT
列是UNSIGNED
,列的范围的大小是相同的,但是它的端点向上移动,从-2147483648和2147483647到0和4294967295。
整数类型可以具有AUTO_INCREMENT
属性。在AUTO_INCREMENT
列中插入NULL
值时,该列将被设置为下一个序列值。通常是value+1
,其中value
是表中当前列的最大值。(AUTO_INCREMENT
序列以1开头。)
将0存储到AUTO_INCREMENT
列中与存储NULL
具有相同的效果,除非启用了NO_AUTO_VALUE_ON_ZERO
SQL模式。
插入NULL
来生成AUTO_INCREMENT
值需要将列声明为NOT NULL
。如果列声明为NULL
,则插入NULL
存储NULL
。当您在AUTO_INCREMENT
列中插入任何其他值时,该列将被设置为该值并重置序列,以便下一个自动生成的值按照插入值的顺序出现。
AUTO_INCREMENT
列不支持负值。
CHECK
约束不能引用具有AUTO_INCREMENT
属性的列,也不能将AUTO_INCREMENT
属性添加到CHECK
约束中使用的现有列中。
当MySQL在列数据类型允许范围之外的数值列中存储值时,结果取决于当时有效的SQL模式:
表示时间值的日期和时间数据类型是DATE
、TIME
、DATETIME
、TIMESTAMP
和YEAR
。每个时间类型都有一个有效值范围,以及一个零值,当你指定一个MySQL无法表示的无效值时,可能会使用这个零值代替。MySQL允许您存储一个零值作为虚拟日期。在某些情况下,这比使用NULL
值更方便,并且使用更少的数据和索引空间。要禁用零值,请启用NO_ZERO_DATE
模式。下表显示了每种类型的零值的格式。零值是特殊的,但是您可以使用表中显示的值显式地存储或引用它们。您也可以使用值'0'
或0
来完成此操作。
类型 | 零值 |
---|---|
DATE | ‘0000-00-00’ |
TIME | ‘00:00:00’ |
DATETIME | ‘0000-00-00 00:00:00’ |
TIMESTAMP | ‘0000-00-00 00:00:00’ |
TEAR | 0000 |
MySQL允许为TIME
、DATETIME
和TIMESTAMP
值设置小数秒,精度可达微秒。要定义包含小数秒部分的列,请使用语法type_name(fsp)
,其中type_name
是类型名,fsp是小数秒精度。例如:
CREATE TABLE t1 (t TIME(3), dt DATETIME(6), ts TIMESTAMP(0));
如果给定fsp值,则必须在0到6的范围内。值为0表示没有小数部分。如果省略,默认精度为0。
DATE
DATETIME[(fsp)]
TIMESTAMP[(fsp)]
TIME[(fsp)]
YEAR
SUM()
和AVG()
聚合函数不能处理时间值。(它们将值转换为数字,丢掉第一个非数字字符之后的所有内容。)要解决此问题,请转换为数字单位,执行聚合操作,然后再转换回临时值。例子:
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(time_col))) FROM tbl_name;
SELECT FROM_DAYS(SUM(TO_DAYS(date_col))) FROM tbl_name;
DATE
、DATETIME
和TIMESTAMP
类型是相关的。本节描述它们的特点、相似之处和不同之处。
DATE
类型用于有日期部分但没有时间部分的值。
'YYYY-MM-DD'
格式检索和显示DATE
值。DATETIME
类型用于同时包含日期和时间部分的值。
'YYYY-MM-DD hh:mm:ss'
格式的DATETIME
值。TIMESTAMP
数据类型用于同时包含日期和时间部分的值。
TIMESTAMP
的取值范围是’1970-01-01 00:00:01’ UTC到’ 20388-01-19 03:14:07’ UTC。TIMESTAMP
值从当前时区转换为UTC进行存储,并将UTC转换回当前时区进行检索。DATETIME
等其他类型不会发生这种情况。默认情况下,每个连接的当前时区是服务器的时间。时区可以基于每个连接进行设置。只要时区设置保持不变,就会得到与存储相同的值。如果你存储了一个TIMESTAMP
值,然后修改了时区并取得了这个值,那么取得的值与你存储的值是不同的。发生这种情况是因为在两个方向的转换中没有使用相同的时区。当前时区可以通过系统变量time_zone
获取。DATETIME
或TIMESTAMP
值可以包含尾部小数秒部分,精度可达微秒。特别是,插入到DATETIME
或TIMESTAMP
列中的值中的任何小数部分都会被存储而不是丢弃。如果包含小数部分,则这些值的格式为'YYYY-MM-DD hh:mm:ss[.fraction]'
, DATETIME
值的范围为’ 10000-01-01 00:00:00.000000’到’ 99999-12-31 23:59:59.499999’,TIMESTAMP
值的范围为’1970-01-01 00:00:01.000000’到’ 20388-01-19 03:14:07.499999’。TIMESTAMP
和DATETIME
数据类型支持对当前日期和时间的自动初始化和更新。DATE
、DATETIME
或TIMESTAMP
值将被转换为相应类型的零值。使用DEFAULT CURRENT_TIMESTAMP
和ON UPDATE CURRENT_TIMESTAMP
子句可以将TIMESTAMP
和DATETIME
列设置为自动初始化并更新为当前日期和时间。自动初始化和更新的时机如下:
如果禁用了explicit_defaults_for_timestamp
系统变量:
TIMESTAMP
列将同时具有DEFAULT CURRENT_TIMESTAMP
和ON UPDATE CURRENT_TIMESTAMP
。TIMESTAMP
列默认NOT NULL
,不能包含NULL
值,指定NULL
值则指定当前时间戳。要允许时间戳列包含NULL
,需要显式地使用NULL
属性声明它。在这种情况下,默认值也会变成NULL
。此时赋值NULL
会将其设置为NULL
,而不是当前时间戳。如果启用了explicit_defaults_for_timestamp
系统变量:
TIMESTAMP
列只有在使用NULL
属性声明时才允许NULL
值。TIMESTAMP
列不允许被赋值为NULL
,无论是用NULL
还是NOT NULL
属性声明。日期和时间值可以用几种格式表示,例如引号字符串或数字,具体取决于值的确切类型和其他因素。例如,在MySQL需要日期的上下文中,它将'2015-07-21'
,'20150721'
和20150721
中的任何一个解释为日期。
标准SQL要求使用类型关键字和字符串指定时间和日期字面量。关键字和字符串之间的空格是可选的。
DATE 'str'
TIME 'str'
TIMESTAMP 'str'
MySQL可以识别,但与标准SQL不同,它不需要类型关键字。要与标准兼容的应用程序应该包括用于时间和日期字面量的类型关键字。
MySQL可以识别以下格式的DATE
值:
'YYYY-MM-DD'
或'YY-MM-DD'
格式的字符串。'YYYYMMDD'
或'YYMMDD'
格式的无分隔符的字符串,前提是该字符串作为日期有意义。如果没有意义则会变成'0000-00-00'
。YYYYMMDD
或YYMMDD
格式的数字,前提是该数字作为日期有意义。MySQL可以识别以下格式的DATETIME
和TIMESTAMP
值:
'YYYY-MM-DD hh:mm:ss'
或'YY-MM-DD hh:mm:ss'
的字符串。'YYYYMMDDhhmmss'
或'YYMMDDhhmmss'
格式的没有分隔符的字符串,前提是该字符串作为日期有意义,没有意义的会变成'0000-00-00 00:00:00'
。YYYYMMDDhhmmss
或YYMMDDhhmmss
格式的数字,前提是该数字作为日期有意义。DATETIME
或TIMESTAMP
值可以包含尾部小数秒部分,精度可达微秒。小数部分与其余部分之间总是要隔一个小数点。
包含两位数年份值的日期是不明确的,因为世纪未知。MySQL使用以下规则解释两位数的年份值:
对于指定为包含日期部分的字符串的值,不需要为小于10的月或日值指定两位数字。' 2015-06-9 '
与’2015-06-09'
相同。类似地,对于指定为包含时间部分的字符串的值,不需要为小于10的小时、分钟或秒值指定两位数字。'2015-10-30 1:2:3'
与'2015-10-30 01:02:03'
相同。
指定为数字的值长度应为6、8、12或14位。如果数字长度为8位或14位,则假定其格式为YYYYMMDD
或YYYYMMDDhhmmss
,并且年份由前4位数字给出。如果数字长度为6或12位,则假定其格式为YYMMDD
或YYMMDDhhmmss
,并且年份由前2位数字给出。不属于这些长度的数字将被解释为在最接近的长度前填充前导零。
指定为非分隔符字符串的值根据其长度进行解释。对于长度为8或14个字符的字符串,年份被假定为前4个字符。否则,年份由前两个字符表示。这个字符串从左到右解析,以查找年、月、日、小时、分钟和秒的值,与字符串中包含的部分相同。这意味着不应该使用少于6个字符的字符串。例如,如果你指定9903
,认为它代表1999年3月,MySQL会将其转换为“0”日期值。这是因为年和月的值分别为99和03,而日部分则完全缺失。但是,您可以显式指定0值来表示缺少的月份或日期部分。例如,要插入值1999-03-00
,使用990300
。
MySQL可以识别以下格式的TIME
值:
'D hh:mm:ss'
格式的字符串'hhmmss'
格式的没有分隔符的字符串,只要它作为时间有意义,无意义的会变成'00:00:00'
。hhmmss
格式的数字,前提是它作为时间有意义。在'D hh:mm:ss.fraction'
、'hh:mm:ss.fraction'
、'hh:mm:ss.fraction'
和'hhmms .fraction'
时间格式中可以识别后面的小数部分,其中fraction
是小数部分,精度最高为微秒。小数部分与其余部分之间总是要隔一个小数点。
对于指定为包含时间部分分隔符的字符串的TIME
值,不需要为小于10的小时、分钟或秒值指定两个数字。'8:3:2'
和'08:03:02'
是一样的。
字符串数据类型包括CHAR
、VARCHAR
、BINARY
、VARBINARY
、BLOB
、TEXT
、ENUM
和SET
。
对于字符串列(CHAR
、VARCHAR
、TEXT
、ENUM
和SET
类型)的定义,MySQL以字符单位解释长度规范。对于二进制字符串列(BINARY
、 VARBINARY
和BLOB
类型)的定义,MySQL以字节单位解释长度规范。
字符串数据类型的列定义可以指定列字符集和排序规则:
CHARACTER SET
指定字符集。如果需要,可以使用COLLATE
属性以及任何其他属性指定字符集的排序规则。CREATE TABLE t
(
c1 VARCHAR(20) CHARACTER SET utf8mb4,
c2 TEXT CHARACTER SET latin1 COLLATE latin1_general_cs
);
CHARACTER SET binary
属性将导致将该列创建为相应的二进制字符串数据类型:CHAR
变为BINARY
,VARCHAR
变为VARBINARY
,TEXT
变为BLOB
。对于ENUM
和SET
数据类型,这种情况不会发生,它们是按照声明创建的。字符串数据类型的列的比较和排序都是基于分配给列的排序规则进行的。
CHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name]
:
0 ~ 255
。如果省略M,则长度为1。CHAR(0)
类型的列。这主要是在您必须与依赖于列的存在但实际上不使用其值的旧应用程序兼容时有用的。当您需要一个只能接受两个值的列时,CHAR(0)
也非常好,因为定义为CHAR(0) NULL
的列只占用一个位,并且只能接受值NULL
和空字符串。VARCHAR(M) [CHARACTER SET charset_name] [COLLATE collation_name]
:
0 ~ 65535
。VARCHAR
的有效最大长度取决于最大行大小和所使用的字符集。例如,utf8mb3
字符每个字符最多需要三个字节,因此可以将使用utf8mb3
字符集的VARCHAR
列声明为最多21,844
个字符。VARCHAR
值存储为1字节或2字节长度的前缀加上数据。长度前缀表示值中包含的字节数。如果值需要不超过255个字节,则VARCHAR
列使用一个长度字节,如果值需要超过255个字节,则使用两个长度字节。BINARY[(M)]
: BINARY
类型类似于CHAR
类型,但存储的是二进制字节字符串而不是非二进制字符串。可选的长度M表示以字节为单位的列长度。如果省略,M默认为1。VARBINARY(M)
:VARBINARY
类型类似于VARCHAR
类型,但存储的是二进制字节字符串,而不是非二进制字符串。M表示以字节为单位的最大列长度。TINYBLOB
:BLOB
列,最大长度为255字节。每个TINYBLOB
值都使用一个1字节长度的前缀来存储,该前缀表示值中的字节数。TINYTEXT [CHARACTER SET charset_name] [COLLATE collation_name]
:TEXT
列,最大长度为255个字符。如果值包含多字节字符,则有效最大长度较小。每个TINYTEXT
值都使用一个1字节长度的前缀来存储,该前缀表示值中的字节数。BLOB[(M)]
:
BLOB
列,最大长度为65,535字节。每个BLOB
值都使用一个2字节长度的前缀来存储,该前缀表示值中的字节数。BLOB
类型,其大小足以容纳M字节长的值。TEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name]
:
TEXT
列,最大长度为65,535个字符。如果值包含多字节字符,则有效最大长度较小。每个TEXT
值都使用一个2字节长度的前缀来存储,该前缀表示值中的字节数TEXT
类型,其大小足以容纳M个字符长的值。MEDIUMBLOB
:BLOB
列,最大长度为16,777,215字节。每个MEDIUMBLOB
值都使用一个3字节长度的前缀来存储,该前缀表示该值的字节数。MEDIUMTEXT [CHARACTER SET charset_name] [COLLATE collation_name]
:TEXT
列,最大长度为16,777,215个字符。如果值包含多字节字符,则有效最大长度较小。每个MEDIUMTEXT
值都使用一个3字节长度的前缀来存储,该前缀表示该值中的字节数。LONGBLOB
:BLOB
列,最大长度为4GB字节。LONGBLOB
列的有效最大长度取决于客户机/服务器协议中配置的最大数据包大小和可用内存。每个LONGBLOB
值都使用一个4字节长度的前缀来存储,该前缀表示值中的字节数。LONGTEXT [CHARACTER SET charset_name] [COLLATE collation_name]
:TEXT
列,最大长度为4GB个字符。如果值包含多字节字符,则有效最大长度较小。LONGTEXT
列的有效最大长度还取决于客户机/服务器协议中配置的最大数据包大小和可用内存。每个LONGTEXT
值都使用一个4字节长度的前缀来存储,该前缀表示该值中的字节数。ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name]
:
'value1', 'value2',…
、NULL
、特殊的''
错误值中选择。ENUM
值在内部表示为整数。ENUM
列最多可以有65,535个不同的元素。ENUM
元素支持的最大长度是 M < = 255 M <= 255 M<=255和 ( M × w ) < = 1020 (M\times w)<= 1020 (M×w)<=1020,其中M是元素文字长度,w是字符集中最大长度字符所需的字节数。SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name]
:
'value1', 'value2',…
中选择。SET
值在内部表示为整数。SET
列最多可以有64个不同的成员。SET
元素支持的最大长度是 M < = 255 M <= 255 M<=255和 ( M × w ) < = 1020 (M\times w)<= 1020 (M×w)<=1020,其中M是元素文字长度,w是字符集中最大长度字符所需的字节数。CHAR
和VARCHAR
类型相似,但存储和检索的方式不同。它们在最大长度和是否保留尾随空格方面也有所不同。
CHAR
和VARCHAR
类型声明了一个长度,该长度指示您希望存储的最大字符数。例如,CHAR(30)
最多可以容纳30个字符。CHAR
列的长度固定为创建表时声明的长度。长度为0 ~ 255
之间的任意值。当存储CHAR
值时,它们用空格右填充到指定的长度。当检索CHAR
值时,除非启用了PAD_CHAR_TO_FULL_LENGTH
SQL模式,否则将删除尾随空格。VARCHAR
列中的值是可变长度的字符串。长度范围为0 ~ 65535
。VARCHAR
的有效最大长度取决于最大行大小和所使用的字符集。与CHAR
相反,VARCHAR
值存储为1字节或2字节长度的前缀加上数据。长度前缀表示值中包含的字节数。如果值需要不超过255个字节,则列使用一个长度字节,如果值需要超过255个字节,则使用两个长度字节。下表通过显示将各种字符串值存储到CHAR(4)
和VARCHAR(4)
列中的结果来说明CHAR
和VARCHAR
之间的区别(假设该列使用单字节字符集)。
表最后一行显示的值仅在不使用严格SQL模式时才适用;如果启用严格模式,则不会存储超过列长度的值,并导致错误。
InnoDB将大于或等于768字节的固定长度字段编码为可变长度字段,可以存储在页外。
BINARY
和VARBINARY
类型类似于CHAR
和VARCHAR
,除了它们存储二进制字符串而不是非二进制字符串。也就是说,它们存储字节字符串而不是字符串。这意味着它们具有二进制字符集和排序,比较和排序基于值中字节的数值。
BINARY
和VARBINARY
允许的最大长度与CHAR
和VARCHAR
相同。
如果没有启用严格的SQL模式,并且您为BINARY
或VARBINARY
列分配的值超过了列的最大长度,则该值将被截断以适合该列,并生成警告。
当BINARY
值被存储时,它们被0x00(零字节)右填充到指定的长度,并且在检索时不删除尾随字节。零字节和空格在比较时不同,零字节排在空格前边。
对于VARBINARY
,插入时没有填充,检索时也不会剥离字节。
对于那些删除尾垫字节或比较忽略它们的情况,如果列具有需要唯一值的索引,则在列中插入仅在尾垫字节数上不同的值将导致重复键错误。例如,如果一个表包含'a'
,尝试存储'a\0'
会导致重复键错误。
如果计划使用BINARY
数据类型存储二进制数据,并且要求检索的值与存储的值完全相同,则应该仔细考虑前面的填充和剥离特征。下面的例子说明了零字节填充如何影响列值比较:
mysql> CREATE TABLE t (c BINARY(3));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t SET c = 'a';
Query OK, 1 row affected (0.01 sec)
mysql> SELECT HEX(c), c = 'a', c = 'a\0\0' from t;
+--------+---------+-------------+
| HEX(c) | c = 'a' | c = 'a\0\0' |
+--------+---------+-------------+
| 610000 | 0 | 1 |
+--------+---------+-------------+
1 row in set (0.09 sec)
如果检索到的值必须与没有填充的存储指定的值相同,那么最好使用VARBINARY
或BLOB
数据类型之一。
BLOB是一种二进制大对象,可以保存可变数量的数据。这四种BLOB类型是TINYBLOB
、BLOB
、MEDIUMBLOB
和LONGBLOB
。它们的不同之处在于它们所能保存的值的最大长度。四种TEXT类型分别是TINYTEXT
、TEXT
、MEDIUMTEXT
和LONGTEXT
。它们对应于四种BLOB类型,并且具有相同的最大长度和存储需求。
BLOB值被视为二进制字符串。它们具有二进制字符集和排序,比较和排序基于列值中字节的数值。TEXT值被视为非二进制字符串。它们具有二进制以外的字符集,并且根据字符集的排序对值进行排序和比较。
如果没有启用严格的SQL模式,并且您为BLOB或TEXT列分配的值超过了列的最大长度,则该值将被截断以适合该列,并生成警告。无论使用何种SQL模式,截断要插入TEXT列的值的多余尾随空格总是会生成警告。
对于TEXT和BLOB列,在插入时没有填充,在选择时也不会剥离字节。如果对TEXT列进行了索引,则索引条目比较将在末尾填充空格。这意味着,如果索引需要唯一的值,则只在末尾空格的数量上不同的值会发生重复键错误。例如,如果一个表包含'a'
,尝试存储'a '
会导致重复键错误。
在大多数情况下,可以将BLOB
列视为VARBINARY
列,其大小可以随您的喜好而定。类似地,您可以将TEXT
列视为VARCHAR
列。BLOB
和TEXT
与VARBINARY
和VARCHAR
的区别如下:
BLOB
列和TEXT
列上的索引,必须指定索引前缀长度。对于CHAR
和VARCHAR
,前缀长度是可选的。BLOB
和TEXT
列不能有DEFAULT
值。因为BLOB和TEXT值可能非常长,所以在使用它们时可能会遇到一些限制:
max_sort_length
字节。max_sort_length
的默认值是1024。通过在服务器启动或运行时增加max_sort_length
的值,可以使排序或分组中有更多重要的字节。SELECT *
,因为它选择所有列。每个BLOB或TEXT值在内部由一个单独分配的对象表示。这与所有其他数据类型不同,其他数据类型在打开表时为每列分配一次存储。
ENUM
是一个字符串对象,其值从允许的值列表中选择,这些值在表创建时在列规范中显式枚举。ENUM
类型有以下优点:
这些潜在的问题需要考虑:
ORDER BY
子句中使用ENUM
列需要格外小心枚举值必须是带引号的字符串字面值。例如,你可以像这样创建一个包含ENUM
列的表:
CREATE TABLE shirts (
name VARCHAR(40),
size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),
('polo shirt','small');
SELECT name, size FROM shirts WHERE size = 'medium';
+---------+--------+
| name | size |
+---------+--------+
| t-shirt | medium |
+---------+--------+
UPDATE shirts SET size = 'small' WHERE size = 'large';
COMMIT;
每个枚举值都有一个索引:
ENUM
值的行:mysql> SELECT * FROM tbl_name WHERE enum_col=0;
NULL
值的索引为NULL
。一个ENUM
列最多可以有65,535个不同的元素。
如果在数字上下文中检索ENUM
值,则返回列值的索引。例如,你可以像这样从ENUM
列中检索数值:
mysql> SELECT enum_col+0 FROM tbl_name;
SUM()
或AVG()
等函数需要一个数字参数,必要时将参数转换为数字。对于ENUM
值,在计算中使用索引号。
创建表时,表定义中的ENUM
成员值中的尾随空格将自动删除。
ENUM
列可以被分配一个字符集和排序规则。对于二进制或区分大小写的排序,在向列赋值时要考虑大小写。
我们强烈建议不要使用数字作为枚举值,因为它不会比适当的TINYINT
或SMALLINT
类型节省存储空间,而且如果不正确地引用ENUM值,很容易混淆字符串和底层数字值。如果确实使用数字作为枚举值,请始终将其括在引号中。如果省略引号,则将该数字视为索引。
在某些情况下,枚举值也可以是空字符串或NULL
:
ENUM
中插入一个无效的值,则将插入空字符串作为一个特殊的错误值。该字符串的索引是0。如果启用了严格SQL模式,尝试插入无效的ENUM
值将导致错误。ENUM
列声明为允许NULL
,则NULL
值是该列的有效值,默认值为NULL
。如果一个ENUM
列被声明为NOT NULL
,它的默认值是允许值列表的第一个元素。ENUM
值根据它们的索引号排序,索引号取决于枚举成员在列规范中列出的顺序。空字符串排在非空字符串之前,NULL
值排在所有其他枚举值之前。为了防止在ENUM
列上使用ORDER BY
子句时出现意外结果,请使用以下技术之一:
ENUM
列表ORDER BY CAST(col AS CHAR)
或ORDER BY CONCAT(col)
,确保列按词法排序,而不是按索引号排序。枚举值不能是表达式,即使是计算结果为字符串值的表达式。例如,这个CREATE TABLE
语句不能工作,因为CONCAT
函数不能用来构造枚举值:
CREATE TABLE sizes (
size ENUM('small', CONCAT('med','ium'), 'large')
);
也不能将用户变量用作枚举值。这对语句不起作用:
SET @mysize = 'medium';
CREATE TABLE sizes (
size ENUM('small', @mysize, 'large')
);
SET
是一个字符串对象,可以有零个或多个值,每个值必须从创建表时指定的允许值列表中选择。由多个集合成员组成的SET
列值用逗号分隔。这样做的结果是SET
成员值本身不应该包含逗号。
一个SET
列最多可以有64个不同的成员。
定义中的重复值会导致警告,如果启用了严格的SQL模式,则会导致错误。
创建表时,表定义中的SET
成员值中的尾随空格将自动删除。
检索时,将使用列定义中使用的字母来显示存储在SET
列中的值。注意,SET
列可以分配一个字符集和排序规则。对于二进制或区分大小写的排序,在向列赋值时要考虑大小写。
MySQL以数字方式存储SET
值,存储值的低位对应于第一个SET
成员。如果在数字上下文中检索SET
值,则检索到的值具有与组成列值的集合成员相对应的位集。例如,你可以像这样从SET
列中检索数值:
mysql> SELECT set_col+0 FROM tbl_name;
如果将一个数字存储在SET
列中,则在该数字的二进制表示中设置的位决定列值中的集合成员。对于指定为SET('a','b','c','d')
的列,成员具有以下十进制和二进制值。
SET成员 | 十进制值 | 二进制值 |
---|---|---|
‘a’ | 1 | 0001 |
‘b’ | 2 | 0010 |
‘c’ | 4 | 0100 |
‘d’ | 8 | 1000 |
如果将值9赋给这一列,那么在二进制中就是1001,因此第一个和第四个SET值成员'a'
和'd'
被选中,结果值为'a,d'
。
对于包含多个SET
元素的值,在插入值时,元素的排列顺序无关紧要。给定元素在值中列出多少次也无关紧要。当稍后检索该值时,值中的每个元素都会出现一次,并根据表创建时指定的顺序列出元素。假设指定一个列为SET('a','b','c','d')
:
mysql> CREATE TABLE myset (col SET('a', 'b', 'c', 'd'));
mysql> INSERT INTO myset (col) VALUES
-> ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d');
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0
然后所有这些值在检索时显示为'a,d'
:
mysql> SELECT col FROM myset;
+------+
| col |
+------+
| a,d |
| a,d |
| a,d |
| a,d |
| a,d |
+------+
5 rows in set (0.04 sec)
如果将SET
列设置为不支持的值,则忽略该值并发出警告:
mysql> INSERT INTO myset (col) VALUES ('a,d,d,s');
Query OK, 1 row affected, 1 warning (0.03 sec)
mysql> SHOW WARNINGS;
+---------+------+------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------+
| Warning | 1265 | Data truncated for column 'col' at row 1 |
+---------+------+------------------------------------------+
1 row in set (0.04 sec)
mysql> SELECT col FROM myset;
+------+
| col |
+------+
| a,d |
| a,d |
| a,d |
| a,d |
| a,d |
| a,d |
+------+
6 rows in set (0.01 sec)
如果启用了严格SQL模式,尝试插入无效的SET值将导致错误。
SET
值按数字排序。NULL
值排在非NULL
SET
值之前。
SUM()
或AVG()
等函数需要一个数字参数,必要时将参数转换为数字。对于SET
值,强制转换操作导致使用数值。
通常,您使用FIND_IN_SET()
函数或LIKE
操作符搜索SET
值:
mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
第一个语句查找set_col
包含值集成员的行。第二个类似,但不相同:它查找set_col
在任何地方包含值的行,即使是作为另一个集合成员的子字符串。
还允许下列声明:
mysql> SELECT * FROM tbl_name WHERE set_col & 1;
mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';
第一个语句查找包含第一个集合成员的值。第二步寻找完全匹配的。对第二种类型的比较要小心。将集合值与'val1,val2'
进行比较所返回的结果与将集合值与'val2,val1'
进行比较所返回的结果不同。您应该按照列定义中列出的顺序指定值。
要确定SET
列的所有可能值,请使用SHOW COLUMNS FROM tbl_name LIKE set_col
,并在输出的Type
列中解析SET
定义。
字符串是一个字节或字符序列,由单引号或双引号字符组成:
'a string'
"another string"
相邻的带引号的字符串被连接成一个字符串。下面几行是等价的:
'a string'
'a' ' ' 'string'
如果启用了ANSI_QUOTES
SQL模式,则字符串字面值只能在单引号内加引号,因为在双引号内加引号的字符串将被解释为标识符。
二进制字符串是一串字节。每个二进制字符串都有一个名为binary
的字符集和排序规则。非二进制字符串是一串字符。它具有binary
以外的字符集和与该字符集兼容的排序规则。
对于这两种类型的字符串,比较都是基于字符串单元的数值。对于二进制字符串,单位是字节;比较使用数字字节值。对于非二进制字符串,单位是字符,一些字符集支持多字节字符;比较使用数字字符代码值。
字符串字面量可以有一个可选的字符集引入器和COLLATE
子句,将其指定为使用特定字符集和排序规则的字符串:
[_charset_name]'string' [COLLATE collation_name]
您可以使用N'literal'
(或n'literal'
)在本地字符集中创建字符串。以下语句是等价的:
SELECT N'some text';
SELECT n'some text';
SELECT _utf8'some text';
在字符串中,除非启用NO_BACKSLASH_ESCAPES
SQL模式,否则某些序列具有特殊含义。这些序列中的每一个都以反斜杠开头,称为转义字符。MySQL识别的转义序列如下表所示。对于不在表中的所有其他转义序列,将忽略反斜杠。
要将二进制数据插入字符串列,应该用转义序列表示某些字符。其中反斜杠和用于引用字符串的引号字符是必须转义的。
在编写应用程序时,任何可能包含这些特殊字符的字符串在作为数据值发送给MySQL服务器的SQL语句中使用之前都必须进行适当的转义。你可以通过两种方式做到这一点:
mysql_real_escape_string_quote()
C API函数来转义字符。如有需要,请看这里。
如有需要,请看这里。
数据类型定义可以具有显式或隐式的默认值。数据类型规范中的DEFAULT value
子句显式地指示列的默认值:
CREATE TABLE t1 (
i INT DEFAULT -1,
c VARCHAR(10) DEFAULT '',
price DOUBLE(16,2) DEFAULT 0.00
);
SERIAL DEFAULT VALUE
是一个特例。在整型列的定义中,它是NOT NULL AUTO_INCREMENT UNIQUE
的别名。
DEFAULT
子句中指定的默认值可以是文字常量或表达式。表达式必须放在括号里:
CREATE TABLE t1 (
-- literal defaults
i INT DEFAULT 0,
c VARCHAR(10) DEFAULT '',
-- expression defaults
f FLOAT DEFAULT (RAND() * RAND()),
b BINARY(16) DEFAULT (UUID_TO_BIN(UUID())),
d DATE DEFAULT (CURRENT_DATE + INTERVAL 1 YEAR),
p POINT DEFAULT (Point(0,0)),
j JSON DEFAULT (JSON_ARRAY())
);
唯一的例外是,对于TIMESTAMP
和DATETIME
列,您可以指定CURRENT_TIMESTAMP
函数作为默认值,而不需要用括号括起来。
BLOB
、TEXT
、GEOMETRY
和JSON
数据类型只能在将值写入表达式时才可以分配默认值,即使表达式值是文字:
CREATE TABLE t2 (b BLOB DEFAULT ('abc'));
CREATE TABLE t2 (b BLOB DEFAULT 'abc');
表达式默认值必须遵循以下规则。如果表达式包含不允许的结构,则会发生错误:
AUTO_INCREMENT
属性的列。ALTER TABLE
对表列进行重新排序。如果结果表的表达式默认值包含对生成的列或具有表达式默认值的列的前向引用,则语句将失败。对于CREATE TABLE ... LIKE
和CREATE TABLE ... SELECT
语句,目标表保留原始表中的表达式默认值。
如果一个表达式的默认值引用了一个不确定的函数,那么任何导致计算该表达式的语句对于基于语句的复制都是不安全的。这包括INSERT
和UPDATE
之类的语句。在这种情况下,如果禁用二进制日志记录,则该语句将正常执行。如果启用二进制日志记录,binlog_format
设置为STATEMENT
,则记录并执行该语句,但会在错误日志中写入警告消息,因为复制从节点可能会偏离。当binlog_format
设置为MIXED
或ROW
时,语句会正常执行。
当插入新行时,可以通过省略列名或将列指定为DEFAULT
来插入带有表达式的列的默认值:
mysql> CREATE TABLE t4 (uid BINARY(16) DEFAULT (UUID_TO_BIN(UUID())));
mysql> INSERT INTO t4 () VALUES();
mysql> INSERT INTO t4 () VALUES(DEFAULT);
mysql> SELECT BIN_TO_UUID(uid) AS uid FROM t4;
+--------------------------------------+
| uid |
+--------------------------------------+
| f1109174-94c9-11e8-971d-3bf1095aa633 |
| f110cf9a-94c9-11e8-971d-3bf1095aa633 |
+--------------------------------------+
并非所有存储引擎都允许表达式默认值。如果没有,则会出现ER_UNSUPPORTED_ACTION_ON_DEFAULT_VAL_GENERATED
错误。
如果默认值的计算结果与声明的列类型不同,则根据通常的MySQL类型转换规则对声明的类型进行隐式强制转换。
除了一个例外,DEFAULT
子句中指定的默认值必须是一个文字常量;它不能是函数或表达式。例外的是,对于TIMESTAMP
和DATETIME
列,您可以指定CURRENT_TIMESTAMP
作为默认值。
不能为BLOB、TEXT、GEOMETRY、JSON
数据类型分配默认值。
如果默认值的计算结果与声明的列类型不同,则根据通常的MySQL类型转换规则对声明的类型进行隐式强制转换。
如果数据类型定义中没有明确的DEFAULT
值,MySQL将按照如下方式确定默认值:
NULL
作为值,则用显式DEFAULT NULL
子句定义该列。NULL
作为值,MySQL定义该列时没有显式的DEFAULT
子句。对于没有显式DEFAULT
子句的NOT NULL
列,如果INSERT
或REPLACE
语句不包含该列的值,或者UPDATE
语句将该列设置为NULL
, MySQL将根据当时有效的SQL模式处理该列:
隐式默认值定义如下:
AUTO_INCREMENT
属性声明类型,默认值是序列中的下一个值。TIMESTAMP
以外的日期和时间类型,默认值是该类型的适当零值。如果启用了explicit_defaults_for_timestamp
系统变量,那么对于TIMESTAMP
也是如此。否则,对于表中的第一个TIMESTAMP
列,默认值是当前日期和时间。ENUM
以外的字符串类型,默认值为空字符串。对于ENUM
,默认值是第一个枚举值。NULL
值表示“无数据”。NULL
可以写成任何字母形式。
NULL
值与数字类型的0或字符串类型的空字符串等值不同。LOAD DATA
或SELECT…INTO OUTFILE
执行的文本文件导入或导出操作。, NULL
由\n
序列表示。ORDER BY
排序,对于升序排序,NULL
值排在其他值之前,对于降序排序,NULL
值排在其他值之后。