6.2 列类型
MySQL 支持大量的列类型,它们可以被分为 3 类:数字类型、日期和时间类型以及字符串(字符)类型。这个章节首先给出可用类型的概述,并且总结各类型所需的存储需求,然后提供各类型中的类型范畴更详细的描述。概述有意地简化了。更详细的说明应该参考特写列类型的附加信息,例如你能为其指定值的允许格式。
MySQL 支持的列类型在下面列出。下列代码字母用于描述中:
- 指出最大的显示尺寸。最大的显示尺寸长度为 255。
-
适用于浮点类型。指出跟随在十进制小数点后的数字数量。最大可能值为 30,但不应大于
M
-2。
M
D
方括号 (“[” and “]”) 指定可选的类型修饰部份。
注意,如果为一个列指定了 ZEROFILL
,MySQL 将自动为这个列添加 UNSIGNED
属性。
警告:你应该知道当在两个整数类型值中使用减法时,如有一个为 UNSIGNED
类型,那么结果也是无符号的。查看章节 6.3.5 Cast 函数。
-
一个非常小的整数。有符号的范围是
-128
到127
。无符号的范围是0
到255
。 -
它们是
TINYINT(1)
的同义词。 -
一个小整数。有符号的范围是
-32768
到32767
。无符号的范围是0
到65535
。 -
一个中等大小的整数。有符号的范围是
-8388608
到8388607
。无符号的范围是0
到16777215
。 -
一个正常大小的整数。有符号的范围是
-2147483648
到2147483647
。无符号的范围是0
到4294967295
。 -
INT
的同义词。 -
一个大的整数。有符号的范围是
-9223372036854775808
到9223372036854775807
。无符号的范围是0
到18446744073709551615
。 你应该知道的有关BIGINT
列的一些事情:- 所有的算术运算均是用有符号的
BIGINT
或DOUBLE
值来完成的,因此你不应该使用大于9223372036854775807
(63 bits) 的无符号大整数,除了位函数之外!如果你这样做了,结果中的某些大数字可能会出错,因为将BIGINT
转换成DOUBLE
时产生了舍入错误。MySQL 4.0 在下列情况下可以处理BIGINT
:- 在一个
BIGINT
列中使用整数存储一个大的无符号值。 - 在
MIN(big_int_column)
和MAX(big_int_column)
中。 - 当两个操作数都是整数时使用操作符 (
+
、-
、*
、等)。
- 在一个
- 通常你可以在一个
BIGINT
列中以字符串方式存储的一个精确的整数。在这种情况下,MySQL 将执行一个字符串到数字的转换,包括无 intermediate 的双精度表示法。 - 当两个参数均是整数值时,“-”、“+”和 “*” 将使用
BIGINT
运算!这就意味着,如果两个大整数的乘积(或函数的结果返回整数)的结果大于9223372036854775807
时,你可能会得到意想不到的结果。
- 所有的算术运算均是用有符号的
-
一个浮点型数字。
precision
可以是<=24
作为一个单精度的浮点数字和介于 25 和 53 之间作为一个双精度的浮点数字。这些类型与下面描述的FLOAT
和DOUBLE
类型相似。FLOAT(X)
有与相应的FLOAT
和DOUBLE
类型同样的范围,但是显示尺寸和十进制小数位数是未定义的。在 MySQL 3.23 中,它是一个真实的浮点值。而在 MySQL 早期的版本中,FLOAT(precision)
通常有 2 小数位。 注意,由于在 MySQL 中所有的计算都是以双精度执行的,所以使用FLOAT
可能带来一些意想不到的问题。查看章节 A.5.6 解决没有匹配行的问题 。 该句法是为了 ODBC 兼容而提供的。 -
一个小的(单精度) 浮点数字。允许的值是
-3.402823466E+38
到-1.175494351E-38
、0
和1.175494351E-38
到3.402823466E+38
。如果UNSIGNED
被指定,负值是不允许的。M
是显示宽度,D
是小数位数。FLOAT
没有参数或有X
<= 24 的FLOAT(X)
代表一个单精度的浮点数字。 -
一个正常大小的(双精度)浮上数字。允许的值是
-1.7976931348623157E+308
到-2.2250738585072014E-308
、0
和2.2250738585072014E-308
到1.7976931348623157E+308
。如果UNSIGNED
被指定,负值是不允许的。M
是显示宽度,D
是小数位数。DOUBLE
没胡参数或有 25 <=X
<= 53 的FLOAT(X)
代表一个双精度的浮点数字。 -
它们是
DOUBLE
同义词。 -
一个未压缩(unpacked)的浮点数。运作如同一个
CHAR
列:“unpacked” 意味着数字是以一个字符串存储的,值的每一位将使用一个字符。小数点并且对于负数,“-” 符号不在M
中计算(但是它们的空间是被保留的)。如果D
是 0,值将没有小数点或小数部份。DECIMAL
值的最大范围与DOUBLE
一致,但是对于一个给定的DECIMAL
列,实际的范围可以被所选择的M
和D
限制。如果UNSIGNED
被指定,负值是不允许的。 如果D
被忽略,缺省为 0。如果M
被忽略,缺省为 10。 在 MySQL 3.23 以前,M
参数必须包含符号与小数点所需的空间。 -
DECIMAL
的同义词。 -
一个日期。支持的范围是
'1000-01-01'
到'9999-12-31'
。MySQL 以'YYYY-MM-DD'
格式显示DATE
值,但是允许你以字符串或数字给一个DATE
列赋值。查看章节 6.2.2.2DATETIME
、DATE
和TIMESTAMP
类型 。 -
一个日期和时间的组合。支持的范围是
'1000-01-01 00:00:00'
到'9999-12-31 23:59:59'
。MySQL 以'YYYY-MM-DD HH:MM:SS'
格式显示DATETIME
值,但是允许你以字符串或数字给一个DATETIME
列赋值。查看章节 6.2.2.2DATETIME
、DATE
和TIMESTAMP
类型 。 -
一个时间戳。范围是
'1970-01-01 00:00:00'
到2037
年间的任意时刻。 MySQL 4.0 和更早版本中,TIMESTAMP
值是以YYYYMMDDHHMMSS
、YYMMDDHHMMSS
、YYYYMMDD
或YYMMDD
格式显示的,它取决于M
是否是14
(或省略)、12
、8
或6
,但是允许你以字符串或数字给一个TIMESTAMP
列赋值。 从 MySQL 4.1 开始,TIMESTAMP
以'YYYY-MM-DD HH:MM:DD'
格式作为字符返回。如果你你希望以数字形式返回则必须在该时间戳字段后加上 +0。不同的时间戳长度是不支持的。从 MySQL 4.0.12 开始,选项--new
可以被用来使服务器与 4.1 一样运作。TIMESTAMP
列有益于记录一个INSERT
或UPDATE
操作的日期和时间,因为如果你自己没有给它赋值,它将被自动地设置为最近一次操作的日期和时间。也可以通过给它赋一个NULL
而使它设置为当前的日期和时间。查看章节 6.2.2 Date 和 Time 类型 。 参数M
只影响一个TIMESTAMP
列的显示格式;它的值总是占用 4 个字节存储。 注意,当TIMESTAMP(M)
列的M
是 8 或 14 时,它返回的是数字而其它的TIMESTAMP(M)
列返回的是字符串。这仅仅是为了可以可靠地转储并恢复到其它格式的表中。查看章节 6.2.2.2DATETIME
、DATE
和TIMESTAMP
类型 。 -
一个时间。范围是
'-838:59:59'
到'838:59:59'
。MySQL 以'HH:MM:SS'
格式显示TIME
值,但是允许你使用字符串或数字来给TIME
列赋值。查看章节 6.2.2.3TIME
类型 。 -
一个 2 或 4 位数字格式的年(缺省为 4 位)。允许的值是
1901
到2155
、0000
(4 位年格式) 以及使用 2 位格式的 1970-2069 (70-69)。MySQL 以YYYY
格式显示YEAR
值,但是允许你使用字符串或数字来给YEAR
列赋值。(YEAR
类型在 MySQL 3.22 之前不支持。) 查看章节 6.2.2.4YEAR
类型 。 -
一个定长的字符串,当存储时,总是以空格填满右边到指定的长度。
M
的范围是 0 到 255 (在 MySQL 3.23 版本之前为 1 到 255)。当该值被检索时,尾部空格将被删除。CHAR
值根据缺省的字符集进行忽略大小写的排索与比较,除非指定了关键词BINARY
。NATIONAL CHAR
(或短形式NCHAR
) 是以 ANSI SQL 方式定义一个CHAR
列,它将使用缺省的字符集。这在 MySQL 中是默认的。CHAR
是CHARACTER
的缩写。 MySQL 允许以CHAR(0)
类型建立一个列。一些老程序运行时必需一个列,却又并不使用这个列的值,你就不得不为了适应它而建立该列,在这情况下,CHAR(0)
将是很有益的。当需要一个列仅保存两个值时:一个为CHAR(0)
(该列没有定义为NOT NULL
),这将仅占用一个比特位来存储 2 个值:NULL
或""
。查看章节 6.2.3.1CHAR
和VARCHAR
类型 。 -
这是
CHAR(1)
的同义词。 -
一个变长的字符串。注意:尾部的空格在存储时将会被删除(这与 ANSI SQL 约规不同)。
M
的范围是 0 到 255 (在 MySQL 4.0.2 之前的版本中是 1 到 255)。VARCHAR
值以大小写忽略方式进行排索与比较,除非关键词BINARY
被指定。查看章节 6.5.3.1 隐式的列定义变化 。VARCHAR
是CHARACTER VARYING
的缩写。查看章节 6.2.3.1CHAR
和VARCHAR
类型 。 -
一个
BLOB
或TEXT
列,最大长度为 255 (2^8 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化 。查看章节 6.2.3.2BLOB
和TEXT
类型 。 -
一个
BLOB
或TEXT
列,最大长度为 65535 (2^16 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化 。查看章节 6.2.3.2BLOB
和TEXT
类型 。 -
一个
BLOB
或TEXT
列,最大长度为 16777215 (2^24 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化 。查看章节 6.2.3.2BLOB
和TEXT
类型 。 -
一个
BLOB
或TEXT
列,最大长度为 4294967295 (2^32 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化 。注意,由于服务器/客户端的协议以及 MyISAM 表通常有一个 16M 每通信包/表行的限制,你仍然不能使用这个类型的整个范围。查看章节 6.2.3.2BLOB
和TEXT
类型 。 -
一个枚举类型。一个仅能有一个值的字符串对象,这个值选自值列
'value1'
、'value2'
、...
、NULL
或特殊的""
出错值。一个ENUM
列可以有最大 65535 不同的值。查看章节 6.2.3.3ENUM
类型 。 -
一个集合。一个能有零个或更多个值的字符串对象,其中每个值必须选自值列
'value1'
、'value2'
、...
。一个SET
列可以有最大 64 个成员。查看章节 6.2.3.4SET
类型 。
TINYINT[(M)] [UNSIGNED] [ZEROFILL]
BIT
BOOL
SMALLINT[(M)] [UNSIGNED] [ZEROFILL]
MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]
INT[(M)] [UNSIGNED] [ZEROFILL]
INTEGER[(M)] [UNSIGNED] [ZEROFILL]
BIGINT[(M)] [UNSIGNED] [ZEROFILL]
FLOAT(precision) [UNSIGNED] [ZEROFILL]
FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]
DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]
DOUBLE PRECISION[(M,D)] [UNSIGNED] [ZEROFILL]
REAL[(M,D)] [UNSIGNED] [ZEROFILL]
DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]
DEC[(M[,D])] [UNSIGNED] [ZEROFILL]
NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL]
DATE
DATETIME
TIMESTAMP[(M)]
TIME
YEAR[(2|4)]
[NATIONAL] CHAR(M) [BINARY]
CHAR
[NATIONAL] VARCHAR(M) [BINARY]
TINYBLOB
TINYTEXT
BLOB
TEXT
MEDIUMBLOB
MEDIUMTEXT
LONGBLOB
LONGTEXT
ENUM('value1','value2',...)
SET('value1','value2',...)
6.2.1 数字类型
MySQL 支持所有的 ANSI/ISO SQL92 数字类型。这些类型包括准确数字的数据类型(NUMERIC
、DECIMAL
、INTEGER
和 SMALLINT
),也包括近似数字的数据类型(FLOAT
、REAL
和 DOUBLE PRECISION
)。关键词 INT
是 INTEGER
的同义词,关键词 DEC
是 DECIMAL
的同义词。
NUMERIC
和 DECIMAL
类型被 MySQL 以同样的类型实现,这在 SQL92 标准中是允许的。他们用于保存对准确精度有重要要求的值,例如与金钱有关的数据。当以它们中的之一声明一个列时,精度和数值范围可以(通常是)被指定;例如:
salary DECIMAL(5,2)
在这个例子中,5
(精度(precision)
) 代表重要的十进制数字的数目,2
(数据范围(scale)
) 代表在小数点后的数字位数。在这种情况下,因此,salary
列可以存储的值范围是从 -99.99
到 99.99
。(实际上 MySQL 在这个列中可以存储的数值可以一直到 999.99
,因为它没有存储正数的符号)。
译者注:
M 与D 对DECIMAL(M, D) 取值范围的影响 类型说明 取值范围(MySQL < 3.23) 取值范围(MySQL >= 3.23) DECIMAL(4, 1) -9.9 到 99.9 -999.9 到 9999.9 DECIMAL(5, 1) -99.9 到 999.9 -9999.9 到 99999.9 DECIMAL(6, 1) -999.9 到 9999.9 -99999.9 到 999999.9 DECIMAL(6, 2) -99.99 到 999.99 -9999.99 到 99999.99 DECIMAL(6, 3) -9.999 到 99.999 -999.999 到 9999.999 # 在MySQL 3.23 及以后的版本中,DECIMAL(M, D) 的取值范围等于早期版本中的DECIMAL(M + 2, D) 的取值范围。注释结束:
在 ANSI/ISO SQL92 中,句法 DECIMAL(p)
等价于 DECIMAL(p,0)
。同样的,在执行被允许决定值 p
的地方,句法 DECIMAL
等价于 DECIMAL(p,0)
。MySQL 目前还不支持 DECIMAL
/NUMERIC
数据类型的这些变体形式中的任一种。一般来说这并不是一个严重的问题,通过明确地控制精度和数值范围可以得到这些类型的主要功能益处。
DECIMAL
和 NUMERIC
值是作为字符串存储的,而不是作为二进制浮点数,以便保护这些值的十进制精确度。一个字符用于数值的每一位、小数点(如果 scale
> 0) 和 “-” 符号(对于负值)。如果 scale
是 0,DECIMAL
和 NUMERIC
值不包含小数点或小数部分。
DECIMAL
和 NUMERIC
值的最大范围与 DOUBLE
一致,但是对于一个给定的 DECIMAL
或 NUMERIC
列,它的实际范围可制定该列时的 precision
或 scale
限制。当这样的列被赋给了小数点的位数超过 scale
所指定的值时,该将根据 scale
进行四舍五入。当一个 DECIMAL
或 NUMERIC
列被赋与一个大小超过指定(或缺省)的 precision
and scale
的限止范围时,MySQL 以该列范围的端点值存储该值。
mysql> CREATE TABLE `tA` ( -> `id` int(4) unsigned zerofill NOT NULL, -> `salary` decimal(5,2), -> PRIMARY KEY (`id`) -> ) TYPE=MyISAM; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO `tA` (`id`, `salary`) -> VALUES (1, -99.99), # 以数字方式插入 -> (2, "99.99"), # 以字符串方式插入 -> (3, -999.99), -> (4, "9999.99"), -> (5, -1000.00), # decimal(5,2)最小范围为 -999.99 该值插入时结果为 -999.99 -> (6, "10000.00"), # decimal(5,2)最大范围为 9999.99 该值插入时结果为 9999.99 -> (7, "-99.999"), # 小数位数超过 scale 指定值,但因以字符串方式插入,结果值仅截去多余部分 -> (8, "99.9999"), -> (9, -99.999), # 小数位数超过 scale 指定值,对该值进行四舍五入,结果为 -100.00 -> (10,99.9999); Query OK, 10 rows affected (0.00 sec) Records: 10 Duplicates: 0 Warnings: 4 mysql> SELECT * FROM `tA`; +------+---------+ | id | salary | +------+---------+ | 0001 | -99.99 | | 0002 | 99.99 | | 0003 | -999.99 | | 0004 | 9999.99 | | 0005 | -999.99 | | 0006 | 9999.99 | | 0007 | -99.99 | | 0008 | 99.99 | | 0009 | -100.00 | | 0010 | 100.00 | +------+---------+ 10 rows in set (0.00 sec) * 以上结果在 MySQL 4.0.12 中测试示例结束(译者注)
作为对 ANSI/ISO SQL92 标准的一个扩展,MySQL 也支持上面的表格所列出的整型类型 TINYINT
、MEDIUMINT
和 BIGINT
。另外一个扩展是 MySQL 支持随意指定一个整型数值的显示格式,这通过在类型的基本关键词后跟一个括号来实现(例如 INT(4)
)。这个可选的宽度规格说明是用于在数值显示时,对某些值的宽度短于该列宽度的值进行左填补显示的,而不是为了限制在该列中存储值的宽度,也不是为了限制那些超过该列指定宽度的值的可被显示的数字位数。当与可选的扩展属性 ZEROFILL
一起使用时,缺省填补用的空格被零代替。举例来说,一个列被定义为 INT(5) ZEROFILL
,插入的值 4
被检索出来时为 00004
。注意,如果在一个整型列中存储一个超过显示宽度的更大值时,当 MySQL 为某些复杂的联结(join)生成临时表时,你可能会遇到问题,因为在这种情况下,MySQL 信任地认为所有的值均适合原始的列宽度。
mysql> CREATE TABLE `tA` ( -> `id` int(4) unsigned zerofill NOT NULL, -> PRIMARY KEY (`id`) -> ) TYPE=MyISAM; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO `tA` (`id`) -> VALUES (1),(12),(1234),(12345678); Query OK, 4 rows affected (0.01 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM `tA`; +----------+ | id | +----------+ | 0001 | | 0012 | | 1234 | | 12345678 | +----------+ 4 rows in set (0.00 sec) * 以上结果在 MySQL 4.0.12 中测试示例结束(译者注)
所有的整型类型可以有一个可选(非标准的)属性 UNSIGNED
。如果希望在一个列中只允许正值并且需要一个稍大一点的数字范围,就可以使用无符号值。
从 MySQL 4.0.2 开始,浮点类型也可以存在 UNSIGNED
。与整型类型一致的,这个属性可以防止在该列中存在负值。而与整型类型不一致的,该列的高部范围仍然与原范围保持一致。
FLOAT
类型被用于表示近似数字的数值类型。ANSI/ISO SQL92 标准允许一个可选的精度说明(但不是指数的范围),跟在 关键词 FLOAT
后的括号内。MySQL 实现也支持这个可选的精度规格说明。当关键词被用于一个列的类型说明而没有精度规格说明时,MySQL 使用四个字节来存储该字段值。在关键词 FLOAT
后的括号里给出两个数字,这种变形的句法也是被支持的。使用这个选项时,第一个数字继续表示值存储所占的字节数,第二个数字指定能被存储和显示的跟随在小数点后的位数(就像 DECIMAL
和 NUMERIC
)。当 MySQL 被要求为这样的一个列存储一个小数点后的小数位数超过指定值的数值时,该值将会被四舍五入,去除额外的位。
mysql> CREATE TABLE `tA` ( -> `id` int(4) unsigned zerofill NOT NULL, -> `float_date` float(4,2) unsigned NOT NULL, -> PRIMARY KEY (`id`) -> ) TYPE=MyISAM; Query OK, 0 rows affected (0.00 sec) mysql> INSERT INTO `tA` (`id`,`float_date`) -> VALUES (1, -100), # 插入无效的负值 -> (2, 100.99), # 以数字方式插入 -> (3, "100.99"), # 以字符串方式插入 -> (4, "100.99999"), # 小数位数超过指定倍数,该值进行四舍五入 -> (5, 100.99999), -> (6, "100.9911"), -> (7, 100.9911); Query OK, 7 rows affected (0.00 sec) Records: 7 Duplicates: 0 Warnings: 1 mysql> SELECT * FROM `tA`; +------+------------+ | id | float_date | +------+------------+ | 0001 | 0.00 | | 0002 | 100.99 | | 0003 | 100.99 | | 0004 | 101.00 | | 0005 | 101.00 | | 0006 | 100.99 | | 0007 | 100.99 | +------+------------+ 7 rows in set (0.00 sec) * 以上结果在 MySQL 4.0.12 中测试示例结束(译者注)
REAL
和 DOUBLE PRECISION
类型不接受精度规格说明。作为对 ANSI/ISO SQL92 标准的扩展,MySQL 接受 DOUBLE
作为 DOUBLE PRECISION
类型的一个同义词。标准要求 REAL
的精度比用于 DOUBLE PRECISION
的更小,而与之相反的,MySQL 以 8 字节的双精度浮点值(当不以“ANSI 模式”运行时)来实现两者。为了得到最大的可移植性, 近似数字的数值存储所需代码应该使用没有精度或小数位数规格说明的 FLOAT
或 DOUBLE PRECISION
类型。
当试图在一个数字列中存储一个超过该列允许范围的值时,MySQL 会剪切该值到范围内的适当端点值,并以结果值代替存储。
举例来说,一个整型列的范围是 -2147483648
到 2147483647
。如果试图在一个 INT
列中插入值 -9999999999
,该值将会被剪切到该范围的低部端点,以 -2147483648
代替存储。同样的,如果试图插入 9999999999
,2147483647
将被代替存储。
如果 INT
列是 UNSIGNED
的,列的范围大小是一致的,不过它的端点移动到了 0
和 4294967295
。如果你试图存储 -9999999999
和 9999999999
,而实际列中存储的值将会变成 0
和 4294967296
。
对于 ALTER TABLE
、LOAD DATA INFILE
、UPDATE
和多行 INSERT
语句,由于剪切发生的转换,将以“Warnings”被报告。
类型 | 占用字节 | 从 | 到 |
TINYINT | 1 | -128 | 127 |
SMALLINT | 2 | -32768 | 32767 |
MEDIUMINT | 3 | -8388608 | 8388607 |
INT | 4 | -2147483648 | 2147483647 |
BIGINT | 8 | -9223372036854775808 | 9223372036854775807 |
6.2.2 Date 和 Time 类型
日期和时间类型有 DATETIME
、DATE
、TIMESTAMP
、TIME
和 YEAR
。每一个类型均有合法值的范围,当给它们赋于一个真正不合法的值时,这些值将会被“零”代替。注意,MySQL 允许存储某个“不严格地”合法的日期,例如 1999-11-31
。这样做的原因是,我们认为应用程序有责任来处理日期合法性的检查,而不是由 SQL 服务器来处理。为了“加快”对日期的检查,MySQL 仅检查月份应在 0-12 范围内,以及天在 0-31 范围内。因为上面所述的范围定义方式,MySQL 因而允许你在一个 DATE
或 DATETIME
列中存储日或月日均为 0 的日期。当一个应用程序希望存储一个出生日期,而你并不知准确的出生日月时,这将变得非常有用。在这种情况下,你可以简单地以 1999-00-00
或 1999-01-00
形式存储日期。(当然你不能期望 DATE_SUB()
或 DATE_ADD
之类的函数能正确地处理这样的日期,并得到正确的值。)
当使用日期和时间类型工作时,这里有一些要记住的总则:
- MySQL 对一个给定的日期或时间类型以标准的格式进行检索,但是它会努力以各种格式匹配解释你所提供的(例如,当你指定一个值,将其赋给一个日期或时间类型或与之比较时)。然而,只在下面部分所描述的格式是被支持的。期望你能够提供合法的值,如果你使用其它格式的值,可能会造成无法预料的结果。
- 尽管 MySQL 会尝试以各种格式解释值,它通常期望日期的年部分放在最左边。日期必须以年-月-日次序给出(例如,
'98-09-04'
),而不是其它地方常用的月-日-年或日-月-年次序(例如,'09-04-98'
、'04-09-98'
)。 - 如果一个值被用于在数字的语境中,MySQL 将自动地将一个日期或时间类型值转换成数字,反之亦然。
- 当 MySQL 遇到一个日期或时间类型的值超出范围或对该类型是一个不合法的值时(查看这个章节的开头部分),它会将该类型的值变换到“零”值。(例外的是超出范围的
TIME
值将被剪切为适当的TIME
范围端点值。) 下表每种类型的“零”值格式:列类型 “零”值 DATETIME
'0000-00-00 00:00:00'
DATE
'0000-00-00'
TIMESTAMP
00000000000000
(长度取决于显示格式)TIME
'00:00:00'
YEAR
0000
- “零”值是特殊的,但是你可以以表中显示的值来明确地存储或引用他们。你也可以使用值
'0'
或0
,这更易于书写。 - 在
MyODBC
2.50.12 和以上的版本中,“零”值的日期和时间值通过MyODBC
将被自动转换成NULL
,因为 ODBC 不能够处理这样的值。
6.2.2.1 Y2K 问题和日期类型
MySQL 自身是 Y2K 安全的(查看章节 1.2.5 2000 年兼容性),但是呈交给 MySQL 的值可能并不是。任何一个包含 2 位年份的值是存在二义性的,因为世纪值是未知的。这样的值必须被解释为 4 位格式,因为 MySQL 内部使用四位存储年份。
对于 DATETIME
、DATE
、TIMESTAMP
和 YEAR
类型,MySQL 使用下列规则解释存在二义性的年份值:
- 在范围
00-69
内的年值被转换为2000-2069
。 - 在范围Y
70-99
内的年值被转换为1970-1999
。
记住,这些规则仅仅提供对于你的数据含义的合理猜测。如果 MySQL 使用的探索法无法得到正确的值,你应该以包含 4 位年份的格式提供一个明确的值。
ORDER BY
将以适当的顺序对 2 位 YEAR/DATE/DATETIME
类型排序。
注意,某些像 MIN()
和 MAX()
之类的函数会将 TIMESTAMP/DATE
转换为一个数字。这就意味着,一个 2 位年份的时间戳将完全不能与这些函数一同工作。在这种情况下,解决的办法是将 TIMESTAMP/DATE
转换为 4 位年份格式或者使用诸如 MIN(DATE_ADD(timestamp,INTERVAL 0 DAYS)) 的方法
。
6.2.2.2 DATETIME
、DATE
和 TIMESTAMP
类型
DATETIME
、DATE
和 TIMESTAMP
类型是相似的。这个章节描述了它们的特性以及它们的相似点与不同点。
DATETIME
类型可用于需要同时包含日期和时间信息的值。MySQL 以 'YYYY-MM-DD HH:MM:SS'
格式检索与显示 DATETIME
类型。支持的范围是 '1000-01-01 00:00:00'
到 '9999-12-31 23:59:59'
。(“支持”的含义是,尽管更早的值可能工作,但不能保证他们均可以。)
DATE
类型可用于需要一个日期值而不需要时间部分时。MySQL 以 'YYYY-MM-DD'
格式检索与显示 DATE
值。支持的范围是 '1000-01-01'
到 '9999-12-31'
。
TIMESTAMP
列类型提供了一种类型,通过它你可以以当前操作的日期和时间自动地标记 INSERT
或UPDATE
操作。如果一张表中有多个 TIMESTAMP
列,只有第一个被自动更新。
自动更新第一个 TIMESTAMP
列在下列任何条件下发生:
- 列值没有明确地在一个
INSERT
或LOAD DATA INFILE
语句中被指定。 - 列值没有明确地在一个
UPDATE
语句中被指定,并且其它的一些列值已发生改变。(注意,当一个UPDATE
设置一个列值为它原有值时,这将不会引起TIMESTAMP
列的更新,因为,如果你设置一个列值为它当前值时,MySQL 为了效率为忽略更新。) - 明确地以
NULL
设置TIMESTAMP
列。
第一个列以外其它 TIMESTAMP
列,可以设置到当前的日期和时间,只要将该列赋值 NULL
或 NOW()
。
任何 TIMESTAMP
列均可以被设置一个不同于当前操作日期与时间的值,这通过为该列明确指定一个你所期望的值来实现。这也适用于第一个 TIMESTAMP
列。这个选择性是很有用的,举例来说,当你希望 TIMESTAMP
列保存该记录行被新添加时的当前的日期和时间,但该值不再发生改变,无论以后是否对该记录行进行过更新:
- 当该记录行被建立时,让 MySQL 设置该列值。这将初始化该列为当前日期和时间。
- 以后当你对该记录行的其它列执行更新时,为
TIMESTAMP
列值明确地指定为它原来的值。
另一方面,你可能发现更容易的方法,使用 DATETIME
列,当新建记录行时以 NOW()
初始化该列,以后在对该记录行进行更新时不再处理它。
示例(译者注):
mysql> CREATE TABLE `tA` ( -> `id` int(3) unsigned NOT NULL auto_increment, -> `date1` timestamp(14) NOT NULL, -> `date2` timestamp(14) NOT NULL, -> PRIMARY KEY (`id`) -> ) TYPE=MyISAM; Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO `tA` SET `id` = 1; Query OK, 1 row affected (0.02 sec) # 没有明确地指定第一个 timestamp 列值,该列值被设为插入的当前时刻 # 没有明确地指定其它的 timestamp 列值,MySQL 则认为插入的是一个非法值,而该列值被设为0 mysql> INSERT INTO `tA` VALUES (2, NOW(), NULL); Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM `tA`; +----+----------------+----------------+ | id | date1 | date2 | +----+----------------+----------------+ | 1 | 20030503104118 | 00000000000000 | | 2 | 20030503104254 | 20030503104254 | +----+----------------+----------------+ 2 rows in set (0.00 sec) mysql> UPDATE `tA` SET `id` = 3 WHERE `id` = 1; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 # 对某一记录行进行了更新,第一个 timestamp 列值也将被更新 mysql> UPDATE `tA` SET `id` = 2 WHERE `id` = 2; Query OK, 0 rows affected (0.00 sec) Rows matched: 1 Changed: 0 Warnings: 0 # MySQL 忽略了这次操作,第一个 timestamp 列值不会被更新 mysql> SELECT * FROM `tA`; +----+----------------+----------------+ | id | date1 | date2 | +----+----------------+----------------+ | 3 | 20030503104538 | 00000000000000 | | 2 | 20030503104254 | 20030503104254 | +----+----------------+----------------+ 2 rows in set (0.00 sec) mysql> UPDATE `tA` SET `id` = 1,`date1`=`date1` WHERE `id` = 3; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 # 明确地指定了第一个 timestamp 列值为它原有值,该值将不会被更新 mysql> SELECT * FROM `tA`; +----+----------------+----------------+ | id | date1 | date2 | +----+----------------+----------------+ | 1 | 20030503104538 | 00000000000000 | | 2 | 20030503104254 | 20030503104254 | +----+----------------+----------------+ 2 rows in set (0.00 sec) * 以上结果在 MySQL 4.0.12 中测试示例结束(译者注)
TIMESTAMP
值可以从 1970 到 2037 之间的任一时刻,精度为一秒。其值作为数字显示。
MySQL 检索与显示 TIMESTAMP
值的格式取决于它的显示尺寸,描述如下表。“完整”的 TIMESTAMP
格式是 14 位的,但是 TIMESTAMP
列可以以一个更短的显示尺寸建立:
列类型 | 显示格式 |
TIMESTAMP(14) | YYYYMMDDHHMMSS |
TIMESTAMP(12) | YYMMDDHHMMSS |
TIMESTAMP(10) | YYMMDDHHMM |
TIMESTAMP(8) | YYYYMMDD |
TIMESTAMP(6) | YYMMDD |
TIMESTAMP(4) | YYMM |
TIMESTAMP(2) | YY |
所有的 TIMESTAMP
列均有一个相同的存储尺寸,而不考虑显示尺寸的大小。最常见的显示尺寸为 6、8、12 和 14。你可以在表创建时指定一个任意的显示尺寸,但是值 0 或 比 14 大的值将会被强制定义为列长 14。在从 1 ~ 13 范围内的奇数会被强制为下一个更大的偶数。
例如(译者注):
字段定义 | 强制字段长度 |
TIMESTAMP(0) | TIMESTAMP(14) |
TIMESTAMP(15) | TIMESTAMP(14) |
TIMESTAMP(1) | TIMESTAMP(2) |
TIMESTAMP(5) | TIMESTAMP(6) |
注意:从 MySQL 4.1 开始,TIMESTAMP
以 'YYYY-MM-DD HH:MM:DD'
格式作为字符串返回。不同的时间戳长度不再被支持。
译者注:如果你你希望在 MySQL 4.1 中以数字形式返回时间戳,则必须在该时间戳字段后加上 +0。从 MySQL 4.0.12 开始,选项 --new 可以被用来使服务器与 4.1 一样运作。
你可以使用常用的格式集中的任何一个指定 DATETIME
、DATE
和 TIMESTAMP
值:
- 一个
'YYYY-MM-DD HH:MM:SS'
或'YY-MM-DD HH:MM:SS'
格式的字符串。一个“宽松”的语法是被允许的:以任何标点符号作为日期部分和时间部分中的定界符。例如,'98-12-31 11:30:45'
、'98.12.31 1+30+45'
、'98/12/31 11*30*45'
和'98@12@31 11^30^45'
均是等价的。 - 一个
'YYYY-MM-DD'
或'YY-MM-DD'
格式的字符串。这里,一个“宽松”的语法同样也是被允许的:例如,'98.12.31'
、'98-12-31'
、'98/12/31'
和'98@12@31'
是等价的。 - 一个无定界符的
'YYYYMMDDHHMMSS'
或'YYMMDDHHMMSS'
格式的字符串,只要字符串看起来像是一个日期。例如,'19970523091528'
和'970523091528'
均被解释为'1997-05-23 09:15:28'
,但是'971122129015'
却是违法的(它的分部分是无意义的),该值被插入时将变成'0000-00-00 00:00:00'
。 - 一个无定界符的
'YYYYMMDD'
或'YYMMDD'
格式的字符串,只要字符串看起来像是一个日期。例如,'19970523'
和'970523'
被解释成为'1997-05-23'
,但是'971332'
却是违法的(它的月和日部分是无意义的),该值被插入时将变成'0000-00-00'
。 - 一个
YYYYMMDDHHMMSS
或YYMMDDHHMMSS
格式的数字,只要数字看起来像是一个日期。例如,19830905132800
和830905132800
被解释成为'1983-09-05 13:28:00'
。 - 一个
YYYYMMDD
或YYMMDD
格式的数字,只要数字看起来像是一个日期。例如,19830905
和830905
被解释成为'1983-09-05'
。 - 在一个
DATETIME
、DATE
或TIMESTAMP
语境中,一个函数的返回值将随之而变化,例如NOW()
或CURRENT_DATE
。
非法的 DATETIME
、DATE
或 TIMESTAMP
值将会被转换到适当形式的“零”值('0000-00-00 00:00:00'
、'0000-00-00'
或 00000000000000
)。
对于以字符串格式指定的包含日期定界符的值,不必要为小于 10
的月或天的值指定 2 位数字。'1979-6-9'
等同于 '1979-06-09'
。同样的,对于以字符串指定的包含时间定界符的值,不必要为小于 10
的时、分或秒指定 2 位数字。'1979-10-30 1:2:3'
等同于 '1979-10-30 01:02:03'
。
以数字指定的值应该是 6、8、12 或 14 位长。如果数字是 8 或 14 位长的,该值将被假定为年份是由头 4 位数字给出的 YYYYMMDD
或 YYYYMMDDHHMMSS
格式。如果数字是 6 或 12 数字长,它将被假定为年份是由头 2 位数字给出的 YYMMDD
或 YYMMDDHHMMSS
格式。不是这些长度之一的数字通过在值前补零到最接近的长度后解释。
以没有定界符的字符串格式指定的值通过它们给出的长度来解释。如果字符串是 8 或 14 个字符长,则假定年份由前 4 个字符给出。否则,年份由前 2 个字符给出。对于字符串中出现的多个部分,字符串以从左到右的顺序被解释,以找出年、月、日、时、分和秒值。这就意味着,你不就使用少于 6 个字符的字符串。例如,如果指定 '9903'
,你可能认为它代表 1999年3月,但你将会发现MySQL 会将一个“零”值插入到你的表中。这是因为,年份和月份分别为 99
和 03
,但是日期部分丢失(为 0),因此这个值是不合法的。
TIMESTAMP
列总是以完全精度存储给定的合法值,而不考虑显示尺寸的大小。这包含几个含义:
- 赋值时总是给出年、月和日,即使你的列类型定义为
TIMESTAMP(4)
或TIMESTAMP(2)
。否则,该值将是不合法的,而被0
代替存储。示例(译者注):
mysql> CREATE TABLE `tA` ( -> `id` int(3) unsigned NOT NULL auto_increment, -> `date1` timestamp(4) NOT NULL, -> PRIMARY KEY (`id`) -> ) TYPE=MyISAM; Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO `tA` (`id`,`date1`) -> VALUES (1,NULL), # 插入当前日期和时间 -> (2,0305), # 以数字格式给出值,而值长度小于 6 ,在最左边补 0 至 6 位数字 -> (3,'0305');# 以字符串格式给出值,而值长不包括年、月和日,因而是一个非法值 Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 1 mysql> SELECT * FROM `tA`; +----+-------+ | id | date1 | +----+-------+ | 1 | 0305 | | 2 | 0003 | | 3 | 0000 | +----+-------+ 3 rows in set (0.00 sec) * 以上结果在 MySQL 4.0.12 中测试
示例结束(译者注) - 如果以
ALTER TABLE
拓展一个TIMESTAMP
窄列,以前被“隐蔽”的信息将被显示出来。示例(译者注):
* 接上例结果 mysql> ALTER TABLE `ta` CHANGE `date1` `date1` TIMESTAMP(11); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 # 设置 `date1` 为 TIMESTAMP(11),MySQL 会自动将其转化为 TIMESTAMP(11) mysql> SELECT * FROM `tA`; +----+--------------+ | id | date1 | +----+--------------+ | 1 | 030503150142 | | 2 | 000305000000 | | 3 | 000000000000 | +----+--------------+ 3 rows in set (0.00 sec) * 以上结果在 MySQL 4.0.12 中测试
示例结束(译者注): - 同样的,缩小一个
TIMESTAMP
列的宽度不会引起信息的丢失,除了在感觉上值在被显示时显示了较少的信息。 - 尽管
TIMESTAMP
列值是以全部精度存储的,但是UNIX_TIMESTAMP()
是唯一能直接操作内部存储值的函数。其它的函数操作的是格式化后的检索的值。这就意味着不能够使用诸如HOUR()
或SECOND()
之类的函数,除非相关部分存在于格式化后的TIMESTAMP
值中。例如,在小于 10 的显示格式上,为了使TIMESTAMP
列中的HH
部分能够显示,显示格式的尺寸必须不小于 10,因此在一个更短的TIMESTAMP
列值上使用HOUR()
将会产生一个无意义的结果。示例(译者注):
* 接上例结果 # 下列示例结果与上述结果相悖 mysql> ALTER TABLE `ta` CHANGE `date1` `date1` TIMESTAMP(4); Query OK, 3 rows affected (0.02 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM `tA`; +----+-------+ | id | date1 | +----+-------+ | 1 | 0305 | | 2 | 0003 | | 3 | 0000 | +----+-------+ 3 rows in set (0.01 sec) mysql> SELECT HOUR(`date1`) FROM `tA`; +---------------+ | Hour(`date1`) | +---------------+ | 15 | | 0 | | NULL | +---------------+ 3 rows in set (0.02 sec) mysql> SELECT SECOND(`date1`) FROM `tA`; +-----------------+ | second(`date1`) | +-----------------+ | 42 | | 0 | | NULL | +-----------------+ 3 rows in set (0.01 sec) * 以上结果在 MySQL 4.0.12 中测试
示例结束(译者注):
在某种程序上,你可以将一个日期值赋给另一种日期类型的对象。然而,这可能会使值产生改变或丢失一部分信息。
- 如果将一个
DATE
值赋给一个DATETIME
或TIMESTAMP
对象,结果值的时间部分将被设为'00:00:00'
,因为DATE
值不包含时间信息。 - 如果将一个
DATETIME
或TIMESTAMP
值赋给一个DATE
对象,结果值的时间部分被删除,因为DATE
类型不能存储时间信息。 - 记住,尽管
DATETIME
、DATE
和TIMESTAMP
值全都可以用同样的格式集来指定,但所有类型不都有同有同样的值范围。例如,TIMESTAMP
值不能早于1970
或晚于2037
。这就意味着,一个日期例如'1968-01-01'
,作为一个DATETIME
或DATE
值是合法的,但不是一个有效的TIMESTAMP
值,当它被赋于一个这样的对象时,它将被转换为0
。
- 你可能会被以字符串指定值时所允许的宽松格式欺骗。例如,一个值如
'10:11:12'
的,因为分界符 “:” 可能看起来像是一个时间值, 但是当它被用于一个日期语境中时,它将被解释成为'2010-11-12'
年。而值'10:45:15'
将被转换成'0000-00-00'
,因为'45'
是一个不合法的月份。 - MySQL 服务器仅对日期的有效性执行基本的检验:天为
00-31
,月为00-12
,年为1000-9999
。任何不是这个范围内的日期将被转换为0000-00-00
。请注意,这仍然允许你存储一个无效的日期例如2002-04-31
。它允许一个 WEB 应用程序不进行进一步的检查而存储一个表单中的数据。为了确保一个日期值的有效性,在你的应用程序里执行有效性检查。 - 以两位数字指定年份是存在二义性的,因为世纪是未知的。MySQL 以下面的规则解释一个 2 位年份值:
00-69
范围的年份值被转换为2000-2069
。70-99
范围的年份值被转换为1970-1999
。
6.2.2.3 TIME
类型
MySQL 以 'HH:MM:SS'
格式(或对大的小时值时使用 'HHH:MM:SS'
格式)检索和显示 TIME
值。TIME
值的范围可以从 '-838:59:59'
到 '838:59:59'
。小时部分可以这么大的原因 是,TIME
类型不仅可以用于表示一天的时间(这一定不会超过 24 小时),而且可以用来表示所经过的时间或两个事件之间的时间间隔(这可能比 24 小时大许多或是一个负值)。
TIME
值可以多种格式指定:
- 一个
'D HH:MM:SS.fraction'
格式的字符串。(注意,MySQL 仍然不能为时间列存储毫秒“fraction”)下面所示的任一种“宽松”的语法均可以被使用:HH:MM:SS.fraction
、HH:MM:SS
、HH:MM
、D HH:MM:SS
、D HH:MM
、D HH
或SS
。这里的D
是一个在 0-33 之间的日期。 - 一个无定界符的
'HHMMSS'
格式的字符串,只要字符串看起来像是一个时间。例如:'101112'
可被理解为'10:11:12'
,但是'109712'
是不合法的(它有一个无意义的分钟部分),当被插入时会转换为'00:00:00'
。 - 一个
HHMMSS
格式的数字,只要数字看起来像一个时间。例如,101112
可被理解为'10:11:12'
。下面的任一格式均可被正常理解:SS
、MMSS
、HHMMSS
、HHMMSS.fraction
。注意,MySQL 仍不能保存 毫秒(fraction)部分。 - 在一个
TIME
语境中,函数(例如CURRENT_TIME
)的返回值将会返一个合理的格式。
对于以字符串指定的包含时间定界符的 TIME
值,不必要为小于 10
的时、分或秒指定 2 位数字。'8:3:2'
与 '08:03:02'
是一致的。
将“短”的 TIME
值赋给另一个 TIME
列时要格外小心。如果没有冒号,MySQL 使用最右位代表秒的假设来解释值。(MySQL 将 TIME
值解释为经过的时间,而不是时刻)。例如,你可能会认为 '1112'
and 1112
的意思就是 '11:12:00'
(11 点过 12 分),但是 MySQL 却将它解释为 '00:11:12'
(11 分,12 秒)。同样的,'12'
和 12
被解释为 '00:00:12'
。有冒号的 TIME
值,由于冒号的存在,通常认为是处理过的时刻。这就是说,'11:12'
就意味着是 '11:12:00'
,而不是 '00:11:12'
。
如果值超出了 TIME
的范围,但是其它分、秒部分是合法的,它将被剪切到取值范围的适当端点。例如,'-850:00:00'
和 '850:00:00'
将被分别转换为 '-838:59:59'
和 '838:59:59'
。
不合法的 TIME
值将被转换为 '00:00:00'
。注意,因为 '00:00:00'
自身是一个合法的 TIME
值,这就没有办法区分,存储在一个表中的 '00:00:00'
,原来的值是否就是指定为 '00:00:00'
或是一个不合法的值。
6.2.2.4 YEAR
类型
YEAR
类型是一个以 1 个字节描述年份的类型。
MySQL 以 YYYY
格式检索和显示一个 YEAR
值。范围是 1901
到 2155
。
可以以多个格式指定 YEAR
值:
- 一个在
'1901'
到'2155'
范围之内的 4 位字符串。 - 一个在
1901
到2155
范围之内的 4 位数字。 - 一个在
'00'
到'99'
范围之内的 2 位字符串。'00'
到'69'
和'70'
到'99'
范围内的值将被分别转换到2000
到2069
和1970
到1999
范围内的YEAR
值。 - 一个在
1
到99
范围之内的数字。1
到69
和70
到99
范围内的值将被分别转换到2001
到2069
和1970
到1999
范围内的YEAR
值。注意,两位数字的范围与两位字符串的范围稍稍有点不同,因为你不能直接地以数字指定一个零值,将它解释为2000
。你必须 以一个'0'
或'00'
格式的字符串指定它,否则它将被解释为0000
。 - 在一个
YEAR
的语境中,函数(例如NOW()
)的返回值将会返回一个合理的格式。
不合法的 YEAR
值将被转换为 0000
。
6.2.3 字符串类型
字符串类型有 CHAR
、VARCHAR
、BLOB
、TEXT
、ENUM
和 SET
。这个章节描述这些类型是如何工作的,它们的存储需求,以及在你的查询中如何使用它们。
类型 | 最大尺寸 | 字节 |
TINYTEXT 或 TINYBLOB | 2^8-1 | 255 |
TEXT 或 BLOB | 2^16-1 (64K-1) | 65535 |
MEDIUMTEXT 或 MEDIUMBLOB | 2^24-1 (16M-1) | 16777215 |
LONGBLOB | 2^32-1 (4G-1) | 4294967295 |
6.2.3.1 CHAR
和 VARCHAR
类型
CHAR
和 VARCHAR
类型是很相似的,但是它们被存储与检索的方式有些不同。
一个 CHAR
列的长度被固定为你创建表进所声明的长度。长度可以是 1 和 255 之间的任一值。(从 MySQL 3.23 之后,CHAR
的长度可以是 0 到 255。)当 CHAR
值被存储时,他们被用空格在右边填补到指定长度。当 CHAR
值被检索时,尾部的空格被截除。
VARCHAR
列的值是变长的字符串。你可以声明一个 VARCHAR
列在 1 到 255, 就像对 CHAR
列一样。然而,与 CHAR
相反的,VARCHAR
值只以所需的字符数存储,另加一个字节存储记录的长度。值并不被填补;相反的,当被存储时,尾部的空格被截除。(这个截除空格方式不同于 ANSI SQL 规约。)
如果将一个超过列最大长度的值赋给一个 CHAR
或 VARCHAR
列,该值将截断以适合它。
下表通过在 CHAR(4)
和 VARCHAR(4)
列中存储不同的字符串的结果显示了两种类型列的不同:
值 | CHAR(4) | 存储需求 | VARCHAR(4) | 存储需求 |
'' | ' ' | 4 字节 | '' | 1 字节 |
'ab' | 'ab ' | 4 字节 | 'ab' | 3 字节 |
'abcd' | 'abcd' | 4 字节 | 'abcd' | 5 字节 |
'abcdefgh' | 'abcd' | 4 字节 | 'abcd' | 5 字节 |
在各种情况下,CHAR(4)
和 VARCHAR(4)
列的检索值均是一样的,因为在 CHAR
列上检索值的尾部空格会被截除。
CHAR
和 VARCHAR
列值以省略字母大小写的方式进行排序和比较,除非在表建立时 BINARY
属性被指定。BINARY
属性意味着,该列值根据 MySQL 服务器正在运行的机器的 ASCII 表顺序进行字母大小写敏感的方式排序和比较。BINARY
并不影响该列如何被存储和检索。
BINARY
属性是有粘性的。这就意味着,如果一个被标记为 BINARY
的列被用于一个表达式中,整个表达式将作为一个 BINARY
值被比较。
在表创建时,MySQL 可能会隐式地改变一个 CHAR
或 VARCHAR
列的类型。查看章节 6.5.3.1 隐式的列定义变化。
6.2.3.2 BLOB
和 TEXT
类型
一个 BLOB
是一个可以保存一可变数量的数据的二进制大对象。四个 BLOB
类型(TINYBLOB
、BLOB
、MEDIUMBLOB
和 LONGBLOB
)之间的不同仅仅在于他们能保存值的最大长度不一致。查看章节 6.2.6 列类型存储需求。
四个 TEXT
类型(TINYTEXT
、TEXT
、MEDIUMTEXT
和 LONGTEXT
)对应与四个 BLOB
类型,并且有相同的最大长度和存储需求。在 BLOB
和 TEXT
类型之间的唯一差别就是,对 BLOB
值是以字母大小写敏感的方式进行排序和比较的,而对 TEXT
值以忽略字母大小写方式进行排序和比较。换句话说,TEXT
是一个忽略字母大小写的 BLOB
。
如果将一个超过列类型最大长度的值赋给一个 BLOB
或 TEXT
列,该值将被截断以适应它。
在大多数方面,可以将一个 TEXT
列看作是一个你所希望大 VARCHAR
列。同样的,BLOB
列可以看作是一个 VARCHAR BINARY
列。差别就在于:
- 在 MySQL 3.23.2 和更新的版本中,可以在
BLOB
和TEXT
列上建立索引。而较老版本的 MySQL 是不支持的。 - 当
BLOB
andTEXT
列值被存储时,尾部的空格不会被剪切,这与VARCHAR
列是不一样的。 BLOB
和TEXT
列不可以有DEFAULT
值。
MyODBC
以 LONGVARBINARY
定义 BLOB
值,以 LONGVARCHAR
定义 TEXT
值。
因为 BLOB
和 TEXT
值可以非常地长,在使用它们时可能会遇到某些限制:
- 如果希望在一个
BLOB
或TEXT
列上使用GROUP BY
和ORDER BY
,必须将该列值转换为一个定长对象。这样做的标准做法是使用SUBSTRING
函数。例如:mysql> SELECT comment FROM tbl_name,SUBSTRING(comment,20) AS substr -> ORDER BY substr;
如果你不这样做,只有列值的前max_sort_length
个字节用于排序。max_sort_length
缺省的值为 1024;在启动mysqld
服务时,可以使用-O
选项对它进行更改。可以在一个包含BLOB
或TEXT
值的表达式上进行分组,通过指定列的位置或使用一个别名:mysql> SELECT id,SUBSTRING(blob_col,1,100) FROM tbl_name GROUP BY 2; mysql> SELECT id,SUBSTRING(blob_col,1,100) AS b FROM tbl_name GROUP BY b;
- 一个
BLOB
或TEXT
对象的最大尺寸由其类型决定,但是在客户端和服务器之间实际所能传送的最大值,是由可用内存总数和通讯缓冲区的大小来决定的。你可以改变报文缓冲区的大小,但必须在服务器端与客户端同时这么做。查看章节 5.5.2 调节服务器参数。
注意,每个 BLOB
或 TEXT
值在内部由一个独立分配的对象表示。这与其它所有的列类型不一样,当表被打开时,它们被按每列分配一次存储。
6.2.3.3 ENUM
类型
ENUM
是一个字符串对象,其值通常选自一个允许值列表中,该列表在表创建时的列规格说明中被明确地列举。
在下列某些情况下,值也可以是空串(""
) 或 NULL
:
- 如果将一个无效值插入一个
ENUM
(即,一个不在允许值列表中的字符串),空字符串将作为一个特殊的错误值被插入。事实上,这个字符串有别于一个“普通的”空字符串,因为这个字符串有个数字索引值为 0。稍后有更详细描述。 - 如果一个
ENUM
被声明为NULL
,NULL
也是该列的一个合法值,并且该列的缺省值也将为NULL
。如果一个ENUM
被声明为NOT NULL
,该列的缺省值将是该列表所允许值的第一个成员。
每个枚举值均有一个索引值:
- 在列说明中列表值所允许的成员值被从 1 开始编号。
- 空字符串错误值的索引值为 0。这就意味着,你可以使用下面所示的
SELECT
语句找出被赋于无效ENUM
值的记录行。mysql> SELECT * FROM tbl_name WHERE enum_col=0;
NULL
值的索引值为NULL
。
例如,指定为 ENUM("one", "two", "three")
的一个列,可以有下面所显示的任一值。每个值的索引值也如下所示:
值 | 索引值 |
NULL | NULL |
"" | 0 |
"one" | 1 |
"two" | 2 |
"three" | 3 |
换个枚举最大可以有 65535 个成员值。
从 MySQL 3.23.51 开始,当表被创建时,ENUM
值尾部的空格将会自动删除。
当为一个 ENUM
列赋值时,字母的大小写是无关紧要的。然而,以后从列中检索出来的值的大小写却是匹配于创建表时所指定的允许值。
如果在一个数字语境中检索一个ENUM
,列值的索引值将被返回。例如,你可以像这样使用数字值检索一个 ENUM
列:
mysql> SELECT enum_col+0 FROM tbl_name;
如果将一个数字存储到一个 ENUM
中,数字被当作为一个索引值,并且存储的值是该索引值所对应的枚举成员。(但是,这在 LOAD DATA
将不能工作,因为它视所有的输入均为字符串。) 在一个 ENUM
字符串中存储数字是不明智的,因为它可能会打乱思维。
ENUM
值依照列规格说明中的列表顺序进行排序。(换句话说,ENUM
值依照它们的索引号排序。)举例来说,对于 ENUM("a", "b")
"a"
排在 "b"
后,但是对于 ENUM("b", "a")
,"b"
却排在 "a"
之前。空字符串排在非空字符串前,NULL
值排在其它所有的枚举值前。为了防止意想不到的结果,建议依照字母的顺序定义 ENUM
列表。也可以通过使用 GROUP BY CONCAT(col)
来确定该以字母顺序排序而不是以索引值。
如果希望得到一个 ENUM
列的所有可能值,可以使用 SHOW COLUMNS FROM table_name LIKE enum_column_name
并分析第二列的 ENUM
定义。
6.2.3.4 SET
类型
SET
是一个字符串对象,它可以有 0 或更多个值,每个值均必须选自一个允许值列表中,该列表在表创建时被指定。包含多个集合成员的 SET
列值,由逗号(“,”)将各成员分隔。由此推论,SET
成员值自身不应该包含逗号。
例如,一个指定为 SET("one", "two") NOT NULL
的列可以有下列任一值:
"" "one" "two" "one,two"
一个 SET
最大可以有 64 个不同的成员。
从 3.23.51 开始,当表被创建时,SET
值尾部的空格将被自动地删除。
MySQL 以数字值存储 SET
值,以被存储值的低阶比特位(bit)对应于第一个集合成员。如果在一个数字语境中检索一个 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")
,那么,"a,d"
、"d,a"
和 "d,a,a,d,d"
在被检索时均将被视为 "a,d"
。
如果将一个不支持的值赋于一个 SET
列,该值将被忽略。
SET
以数字顺序排序。NULL
值排在非 NULL
SET
值之前。
通常,可以使用 LIKE
操作符或 FIND_IN_SET()
函数执行在一个 SET
列上的 SELECT
:
mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%'; mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
但是,下列示例也可以工作:
mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2'; mysql> SELECT * FROM tbl_name WHERE set_col & 1;
第一个语句寻找一个精确的匹配。第二个语句寻找包含第一个集合成员的值。
如果希望得到一个 SET
列的所有可能值,可以使用 SHOW COLUMNS FROM table_name LIKE set_column_name
并分析第二列的 SET
定义。
6.2.4 为列选择正确的类型
为了更有效地使用存储空间,在任何情况下均尝试使用最精确的类型。例如,如果一个整数列被用于在 1
和 99999
之间的值,MEDIUMINT UNSIGNED
是最好的类型。
精确地表示货币值是一个常见的问题。在 MySQL 中,可以使用 DECIMAL
类型。它是作为一个字符串存储的,因而不会发生精度损失的情况。如果精度不是太重要的,那 DOUBLE
类型也是一个不错的选择。
对于高精度,总是能转换一个存储在 BIGINT
中的定点类型。这将允许你以整型进行任何的计算,并在必要的时候将结果转换回浮点值。
6.2.5 使用来自其它的数据库引擎的列类型
为了更容易地使用为其它供应商的 SQL 实现而编写的代码,MySQL 以下表所示的形式映射列类型。这些映射使得从其它数据库引擎移动表到 MySQL 更容易:
其它提供商的类型 | MySQL 类型 |
BINARY(NUM) | CHAR(NUM) BINARY |
CHAR VARYING(NUM) | VARCHAR(NUM) |
FLOAT4 | FLOAT |
FLOAT8 | DOUBLE |
INT1 | TINYINT |
INT2 | SMALLINT |
INT3 | MEDIUMINT |
INT4 | INT |
INT8 | BIGINT |
LONG VARBINARY | MEDIUMBLOB |
LONG VARCHAR | MEDIUMTEXT |
MIDDLEINT | MEDIUMINT |
VARBINARY(NUM) | VARCHAR(NUM) BINARY |
列类型映射在表创建时发生。如果你使用其它供应商使用的类型创建一个表,然后发出一个 DESCRIBE tbl_name
语句,MySQL 将使用相等价的 MySQL 类型报告表结构。
6.2.6 列类型存储需求
每个由 MySQL 支持的列类型的存储需求按类型在下面列出。
6.2.6.1 数字类型存储需求
列类型 | 存储需求 |
TINYINT | 1 字节 |
SMALLINT | 2 字节 |
MEDIUMINT | 3 字节 |
INT | 4 字节 |
INTEGER | 4 字节 |
BIGINT | 8 字节 |
FLOAT(X) | 4 if X <= 24 or 8 ,if 25 <= X <= 53 |
FLOAT | 4 字节 |
DOUBLE | 8 字节 |
DOUBLE PRECISION | 8 字节 |
REAL | 8 字节 |
DECIMAL(M,D) | M+2 字节 if D > 0,M+1 字节 if D = 0 (D +2, if M < D ) |
NUMERIC(M,D) | M+2 字节 if D > 0, M+1 字节 if D = 0 (D +2, if M < D ) |
6.2.6.2 日期和时间类型存储需求
列类型 | 存储需求 |
DATE | 3 字节 |
DATETIME | 8 字节 |
TIMESTAMP | 4 字节 |
TIME | 3 字节 |
YEAR | 1 字节 |
6.2.6.3 字符串类型存储需求
列类型 | 存储需求 |
CHAR(M) | M 字节, 1 <= M <= 255 |
VARCHAR(M) | L +1 字节, where L <= M and 1 <= M <= 255 |
TINYBLOB , TINYTEXT | L +1 字节, where L < 2^8 |
BLOB , TEXT | L +2 字节, where L < 2^16 |
MEDIUMBLOB , MEDIUMTEXT | L +3 字节, where L < 2^24 |
LONGBLOB , LONGTEXT | L +4 字节, where L < 2^32 |
ENUM('value1','value2',...) | 1 or 2 字节, 取决于枚举值的数量(最大值为 65535) |
SET('value1','value2',...) | 1, 2, 3, 4 or 8 字节, 取决于集合成员数量(最大 64 个成员) |
VARCHAR
和 BLOB
和 TEXT
类型是变长的类型,其存储需求取决于列值的实际长度(上表中以 L
表示),而不是取决于类型的最大可能尺寸。例如,一个 VARCHAR(10)
列可以保存最大长度为 10 个字符的字符串。实际存储需求为字符串长度 (L
),再加上 1 个字节用于记录该字符串的长度。对于字符串 'abcd'
,L
为 4,它的存储需求为 5 字节。
BLOB
和 TEXT
类型需要 1、2、3 或 4 字节记录列值的长度,这取决于该类型的最大可能长度。查看章节 6.2.3.2 BLOB
和 TEXT
类型。
如果一个表包含任何变长类型的列类型,记录格式也将是变长的。注意,当一个表被创建时,在某种情况下,MySQL 会将一个列从一个变长类型转换成一个定长类型,或相反的。查看章节 6.5.3.1 隐式的列定义变化。
一个 ENUM
对象的大小取决于不同枚举值的数量。一个字节被用于枚举时,最大可支持 255 个可能值。2 个字节被用于枚举时,最大可支持到 65535 个值。查看章节 6.2.3.3 ENUM
类型。
一个 SET
对象的大小取决于不同集合成员的数量。如果集合的大小是 N
,则对象占用 (N+7)/8
个字节,四舍五入为 1、2、3、4 或 8 个字节。一个 SET
可以有最多 64 个成员。查看章节 6.2.3.4 SET
类型。
MyISAM
表的记录行最大尺寸为 65534 字节。每个 BLOB
和 TEXT
列只占用相对于这个尺寸中的 5-9 个字节。