MySQL Reference Manual for version 4.1.0-alpha.


6.2 列类型

MySQL 支持大量的列类型,它们可以被分为 3 类:数字类型、日期和时间类型以及字符串(字符)类型。这个章节首先给出可用类型的概述,并且总结各类型所需的存储需求,然后提供各类型中的类型范畴更详细的描述。概述有意地简化了。更详细的说明应该参考特写列类型的附加信息,例如你能为其指定值的允许格式。

MySQL 支持的列类型在下面列出。下列代码字母用于描述中:

M
指出最大的显示尺寸。最大的显示尺寸长度为 255。
D
适用于浮点类型。指出跟随在十进制小数点后的数字数量。最大可能值为 30,但不应大于 M-2。

方括号 (“[” and “]”) 指定可选的类型修饰部份。

注意,如果为一个列指定了 ZEROFILL,MySQL 将自动为这个列添加 UNSIGNED 属性。

警告:你应该知道当在两个整数类型值中使用减法时,如有一个为 UNSIGNED类型,那么结果也是无符号的。查看章节 6.3.5 Cast 函数

TINYINT[(M)] [UNSIGNED] [ZEROFILL]
一个非常小的整数。有符号的范围是 -128127。无符号的范围是 0255
BIT
BOOL
它们是 TINYINT(1) 的同义词。
SMALLINT[(M)] [UNSIGNED] [ZEROFILL]
一个小整数。有符号的范围是 -3276832767。无符号的范围是 065535
MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]
一个中等大小的整数。有符号的范围是 -83886088388607。无符号的范围是 016777215
INT[(M)] [UNSIGNED] [ZEROFILL]
一个正常大小的整数。有符号的范围是 -21474836482147483647。无符号的范围是 04294967295
INTEGER[(M)] [UNSIGNED] [ZEROFILL]
INT 的同义词。
BIGINT[(M)] [UNSIGNED] [ZEROFILL]
一个大的整数。有符号的范围是 -92233720368547758089223372036854775807。无符号的范围是 018446744073709551615。 你应该知道的有关 BIGINT 列的一些事情:
FLOAT(precision) [UNSIGNED] [ZEROFILL]
一个浮点型数字。precision 可以是 <=24 作为一个单精度的浮点数字和介于 25 和 53 之间作为一个双精度的浮点数字。这些类型与下面描述的 FLOATDOUBLE 类型相似。 FLOAT(X) 有与相应的 FLOATDOUBLE 类型同样的范围,但是显示尺寸和十进制小数位数是未定义的。 在 MySQL 3.23 中,它是一个真实的浮点值。而在 MySQL 早期的版本中,FLOAT(precision) 通常有 2 小数位。 注意,由于在 MySQL 中所有的计算都是以双精度执行的,所以使用 FLOAT 可能带来一些意想不到的问题。 查看章节 A.5.6 解决没有匹配行的问题 该句法是为了 ODBC 兼容而提供的。
FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]
一个小的(单精度) 浮点数字。允许的值是 -3.402823466E+38-1.175494351E-3801.175494351E-383.402823466E+38。如果 UNSIGNED 被指定,负值是不允许的。M 是显示宽度,D 是小数位数。FLOAT 没有参数或有 X <= 24 的 FLOAT(X) 代表一个单精度的浮点数字。
DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]
一个正常大小的(双精度)浮上数字。允许的值是 -1.7976931348623157E+308-2.2250738585072014E-30802.2250738585072014E-3081.7976931348623157E+308。如果 UNSIGNED 被指定,负值是不允许的。M 是显示宽度,D 是小数位数。DOUBLE 没胡参数或有 25 <= X <= 53 的 FLOAT(X) 代表一个双精度的浮点数字。
DOUBLE PRECISION[(M,D)] [UNSIGNED] [ZEROFILL]
REAL[(M,D)] [UNSIGNED] [ZEROFILL]
它们是 DOUBLE 同义词。
DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]
一个未压缩(unpacked)的浮点数。运作如同一个 CHAR 列:“unpacked” 意味着数字是以一个字符串存储的,值的每一位将使用一个字符。小数点并且对于负数,“-” 符号不在 M 中计算(但是它们的空间是被保留的)。如果 D 是 0,值将没有小数点或小数部份。DECIMAL 值的最大范围与 DOUBLE 一致,但是对于一个给定的 DECIMAL 列,实际的范围可以被所选择的 MD 限制。如果 UNSIGNED 被指定,负值是不允许的。 如果 D 被忽略,缺省为 0。如果 M 被忽略,缺省为 10。 在 MySQL 3.23 以前,M 参数必须包含符号与小数点所需的空间。
DEC[(M[,D])] [UNSIGNED] [ZEROFILL]
NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL]
DECIMAL 的同义词。
DATE
一个日期。支持的范围是 '1000-01-01''9999-12-31'。MySQL 以 'YYYY-MM-DD' 格式显示 DATE 值,但是允许你以字符串或数字给一个 DATE 列赋值。查看章节 6.2.2.2 DATETIMEDATETIMESTAMP 类型
DATETIME
一个日期和时间的组合。支持的范围是 '1000-01-01 00:00:00''9999-12-31 23:59:59'。MySQL 以'YYYY-MM-DD HH:MM:SS' 格式显示 DATETIME 值,但是允许你以字符串或数字给一个 DATETIME 列赋值。查看章节 6.2.2.2 DATETIMEDATETIMESTAMP 类型
TIMESTAMP[(M)]
一个时间戳。范围是 '1970-01-01 00:00:00'2037 年间的任意时刻。 MySQL 4.0 和更早版本中,TIMESTAMP 值是以 YYYYMMDDHHMMSSYYMMDDHHMMSSYYYYMMDDYYMMDD 格式显示的,它取决于 M 是否是 14 (或省略)、1286,但是允许你以字符串或数字给一个 TIMESTAMP 列赋值。 从 MySQL 4.1 开始,TIMESTAMP'YYYY-MM-DD HH:MM:DD' 格式作为字符返回。如果你你希望以数字形式返回则必须在该时间戳字段后加上 +0。不同的时间戳长度是不支持的。从 MySQL 4.0.12 开始,选项 --new 可以被用来使服务器与 4.1 一样运作。 TIMESTAMP 列有益于记录一个 INSERTUPDATE 操作的日期和时间,因为如果你自己没有给它赋值,它将被自动地设置为最近一次操作的日期和时间。也可以通过给它赋一个 NULL 而使它设置为当前的日期和时间。查看章节 6.2.2 Date 和 Time 类型。 参数 M 只影响一个 TIMESTAMP 列的显示格式;它的值总是占用 4 个字节存储。 注意,当 TIMESTAMP(M) 列的 M 是 8 或 14 时,它返回的是数字而其它的 TIMESTAMP(M) 列返回的是字符串。这仅仅是为了可以可靠地转储并恢复到其它格式的表中。 查看章节 6.2.2.2 DATETIMEDATETIMESTAMP 类型
TIME
一个时间。范围是 '-838:59:59''838:59:59'。MySQL 以 'HH:MM:SS' 格式显示 TIME 值,但是允许你使用字符串或数字来给 TIME 列赋值。查看章节 6.2.2.3 TIME 类型
YEAR[(2|4)]
一个 2 或 4 位数字格式的年(缺省为 4 位)。允许的值是 190121550000(4 位年格式) 以及使用 2 位格式的 1970-2069 (70-69)。MySQL 以 YYYY 格式显示 YEAR 值,但是允许你使用字符串或数字来给 YEAR 列赋值。(YEAR 类型在 MySQL 3.22 之前不支持。) 查看章节 6.2.2.4 YEAR 类型
[NATIONAL] CHAR(M) [BINARY]
一个定长的字符串,当存储时,总是以空格填满右边到指定的长度。M 的范围是 0 到 255 (在 MySQL 3.23 版本之前为 1 到 255)。当该值被检索时,尾部空格将被删除。CHAR 值根据缺省的字符集进行忽略大小写的排索与比较,除非指定了关键词 BINARYNATIONAL CHAR (或短形式 NCHAR) 是以 ANSI SQL 方式定义一个 CHAR 列,它将使用缺省的字符集。这在 MySQL 中是默认的。 CHARCHARACTER 的缩写。 MySQL 允许以 CHAR(0) 类型建立一个列。一些老程序运行时必需一个列,却又并不使用这个列的值,你就不得不为了适应它而建立该列,在这情况下,CHAR(0) 将是很有益的。当需要一个列仅保存两个值时:一个为 CHAR(0)(该列没有定义为 NOT NULL),这将仅占用一个比特位来存储 2 个值:NULL""。查看章节 6.2.3.1 CHARVARCHAR 类型
CHAR
这是 CHAR(1) 的同义词。
[NATIONAL] VARCHAR(M) [BINARY]
一个变长的字符串。注意:尾部的空格在存储时将会被删除(这与 ANSI SQL 约规不同)。M 的范围是 0 到 255 (在 MySQL 4.0.2 之前的版本中是 1 到 255)。 VARCHAR 值以大小写忽略方式进行排索与比较,除非关键词 BINARY 被指定。查看章节 6.5.3.1 隐式的列定义变化VARCHARCHARACTER VARYING 的缩写。 查看章节 6.2.3.1 CHARVARCHAR 类型
TINYBLOB
TINYTEXT
一个 BLOBTEXT 列,最大长度为 255 (2^8 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化。查看章节 6.2.3.2 BLOBTEXT 类型
BLOB
TEXT
一个 BLOBTEXT 列,最大长度为 65535 (2^16 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化。查看章节 6.2.3.2 BLOBTEXT 类型
MEDIUMBLOB
MEDIUMTEXT
一个 BLOBTEXT 列,最大长度为 16777215 (2^24 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化。查看章节 6.2.3.2 BLOBTEXT 类型
LONGBLOB
LONGTEXT
一个 BLOBTEXT 列,最大长度为 4294967295 (2^32 - 1) 个字符。查看章节 6.5.3.1 隐式的列定义变化。注意,由于服务器/客户端的协议以及 MyISAM 表通常有一个 16M 每通信包/表行的限制,你仍然不能使用这个类型的整个范围。查看章节 6.2.3.2 BLOBTEXT 类型
ENUM('value1','value2',...)
一个枚举类型。一个仅能有一个值的字符串对象,这个值选自值列 'value1''value2'...NULL 或特殊的 "" 出错值。一个 ENUM 列可以有最大 65535 不同的值。查看章节 6.2.3.3 ENUM 类型
SET('value1','value2',...)
一个集合。一个能有零个或更多个值的字符串对象,其中每个值必须选自值列'value1''value2'...。一个 SET 列可以有最大 64 个成员。查看章节 6.2.3.4 SET 类型

6.2.1 数字类型

MySQL 支持所有的 ANSI/ISO SQL92 数字类型。这些类型包括准确数字的数据类型(NUMERICDECIMALINTEGERSMALLINT),也包括近似数字的数据类型(FLOATREALDOUBLE PRECISION)。关键词 INTINTEGER 的同义词,关键词 DECDECIMAL 的同义词。

NUMERICDECIMAL 类型被 MySQL 以同样的类型实现,这在 SQL92 标准中是允许的。他们用于保存对准确精度有重要要求的值,例如与金钱有关的数据。当以它们中的之一声明一个列时,精度和数值范围可以(通常是)被指定;例如:

    salary DECIMAL(5,2)

在这个例子中,5 (精度(precision)) 代表重要的十进制数字的数目,2 (数据范围(scale)) 代表在小数点后的数字位数。在这种情况下,因此,salary 列可以存储的值范围是从 -99.9999.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 数据类型的这些变体形式中的任一种。一般来说这并不是一个严重的问题,通过明确地控制精度和数值范围可以得到这些类型的主要功能益处。

DECIMALNUMERIC 值是作为字符串存储的,而不是作为二进制浮点数,以便保护这些值的十进制精确度。一个字符用于数值的每一位、小数点(如果 scale > 0) 和 “-” 符号(对于负值)。如果 scale 是 0,DECIMALNUMERIC 值不包含小数点或小数部分。

DECIMALNUMERIC 值的最大范围与 DOUBLE 一致,但是对于一个给定的 DECIMALNUMERIC 列,它的实际范围可制定该列时的 precisionscale 限制。当这样的列被赋给了小数点的位数超过 scale 所指定的值时,该将根据 scale 进行四舍五入。当一个 DECIMALNUMERIC 列被赋与一个大小超过指定(或缺省)的 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 也支持上面的表格所列出的整型类型 TINYINTMEDIUMINTBIGINT。另外一个扩展是 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 后的括号里给出两个数字,这种变形的句法也是被支持的。使用这个选项时,第一个数字继续表示值存储所占的字节数,第二个数字指定能被存储和显示的跟随在小数点后的位数(就像 DECIMALNUMERIC)。当 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 中测试
示例结束(译者注)

REALDOUBLE PRECISION 类型不接受精度规格说明。作为对 ANSI/ISO SQL92 标准的扩展,MySQL 接受 DOUBLE 作为 DOUBLE PRECISION 类型的一个同义词。标准要求 REAL 的精度比用于 DOUBLE PRECISION 的更小,而与之相反的,MySQL 以 8 字节的双精度浮点值(当不以“ANSI 模式”运行时)来实现两者。为了得到最大的可移植性, 近似数字的数值存储所需代码应该使用没有精度或小数位数规格说明的 FLOATDOUBLE PRECISION 类型。

当试图在一个数字列中存储一个超过该列允许范围的值时,MySQL 会剪切该值到范围内的适当端点值,并以结果值代替存储。

举例来说,一个整型列的范围是 -21474836482147483647。如果试图在一个 INT 列中插入值 -9999999999,该值将会被剪切到该范围的低部端点,以 -2147483648 代替存储。同样的,如果试图插入 99999999992147483647 将被代替存储。

如果 INT 列是 UNSIGNED的,列的范围大小是一致的,不过它的端点移动到了 04294967295。如果你试图存储 -99999999999999999999,而实际列中存储的值将会变成 04294967296

对于 ALTER TABLELOAD DATA INFILEUPDATE 和多行 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 类型

日期和时间类型有 DATETIMEDATETIMESTAMPTIMEYEAR。每一个类型均有合法值的范围,当给它们赋于一个真正不合法的值时,这些值将会被“零”代替。注意,MySQL 允许存储某个“不严格地”合法的日期,例如 1999-11-31。这样做的原因是,我们认为应用程序有责任来处理日期合法性的检查,而不是由 SQL 服务器来处理。为了“加快”对日期的检查,MySQL 仅检查月份应在 0-12 范围内,以及天在 0-31 范围内。因为上面所述的范围定义方式,MySQL 因而允许你在一个 DATEDATETIME 列中存储日或月日均为 0 的日期。当一个应用程序希望存储一个出生日期,而你并不知准确的出生日月时,这将变得非常有用。在这种情况下,你可以简单地以 1999-00-001999-01-00 形式存储日期。(当然你不能期望 DATE_SUB()DATE_ADD 之类的函数能正确地处理这样的日期,并得到正确的值。)

当使用日期和时间类型工作时,这里有一些要记住的总则:

6.2.2.1 Y2K 问题和日期类型

MySQL 自身是 Y2K 安全的(查看章节 1.2.5 2000 年兼容性),但是呈交给 MySQL 的值可能并不是。任何一个包含 2 位年份的值是存在二义性的,因为世纪值是未知的。这样的值必须被解释为 4 位格式,因为 MySQL 内部使用四位存储年份。

对于 DATETIMEDATETIMESTAMPYEAR 类型,MySQL 使用下列规则解释存在二义性的年份值:

记住,这些规则仅仅提供对于你的数据含义的合理猜测。如果 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 DATETIMEDATETIMESTAMP 类型

DATETIMEDATETIMESTAMP 类型是相似的。这个章节描述了它们的特性以及它们的相似点与不同点。

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 列类型提供了一种类型,通过它你可以以当前操作的日期和时间自动地标记 INSERTUPDATE 操作。如果一张表中有多个 TIMESTAMP 列,只有第一个被自动更新。

自动更新第一个 TIMESTAMP 列在下列任何条件下发生:

第一个列以外其它 TIMESTAMP 列,可以设置到当前的日期和时间,只要将该列赋值 NULLNOW()

任何 TIMESTAMP 列均可以被设置一个不同于当前操作日期与时间的值,这通过为该列明确指定一个你所期望的值来实现。这也适用于第一个 TIMESTAMP 列。这个选择性是很有用的,举例来说,当你希望 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 一样运作。

你可以使用常用的格式集中的任何一个指定 DATETIMEDATETIMESTAMP 值:

非法的 DATETIMEDATETIMESTAMP 值将会被转换到适当形式的“零”值('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 位数字给出的 YYYYMMDDYYYYMMDDHHMMSS 格式。如果数字是 6 或 12 数字长,它将被假定为年份是由头 2 位数字给出的 YYMMDDYYMMDDHHMMSS 格式。不是这些长度之一的数字通过在值前补零到最接近的长度后解释。

以没有定界符的字符串格式指定的值通过它们给出的长度来解释。如果字符串是 8 或 14 个字符长,则假定年份由前 4 个字符给出。否则,年份由前 2 个字符给出。对于字符串中出现的多个部分,字符串以从左到右的顺序被解释,以找出年、月、日、时、分和秒值。这就意味着,你不就使用少于 6 个字符的字符串。例如,如果指定 '9903' ,你可能认为它代表 1999年3月,但你将会发现MySQL 会将一个“零”值插入到你的表中。这是因为,年份和月份分别为 9903,但是日期部分丢失(为 0),因此这个值是不合法的。

TIMESTAMP 列总是以完全精度存储给定的合法值,而不考虑显示尺寸的大小。这包含几个含义:

在某种程序上,你可以将一个日期值赋给另一种日期类型的对象。然而,这可能会使值产生改变或丢失一部分信息。

当指定日期值时,当心某些失误:

6.2.2.3 TIME 类型

MySQL 以 'HH:MM:SS' 格式(或对大的小时值时使用 'HHH:MM:SS' 格式)检索和显示 TIME 值。TIME 值的范围可以从 '-838:59:59''838:59:59'。小时部分可以这么大的原因 是,TIME 类型不仅可以用于表示一天的时间(这一定不会超过 24 小时),而且可以用来表示所经过的时间或两个事件之间的时间间隔(这可能比 24 小时大许多或是一个负值)。

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 值。范围是 19012155

可以以多个格式指定 YEAR 值:

不合法的 YEAR 值将被转换为 0000

6.2.3 字符串类型

字符串类型有 CHARVARCHARBLOBTEXTENUMSET。这个章节描述这些类型是如何工作的,它们的存储需求,以及在你的查询中如何使用它们。

类型 最大尺寸 字节
TINYTEXTTINYBLOB 2^8-1 255
TEXTBLOB 2^16-1 (64K-1) 65535
MEDIUMTEXTMEDIUMBLOB 2^24-1 (16M-1) 16777215
LONGBLOB 2^32-1 (4G-1) 4294967295

6.2.3.1 CHARVARCHAR 类型

CHARVARCHAR 类型是很相似的,但是它们被存储与检索的方式有些不同。

一个 CHAR 列的长度被固定为你创建表进所声明的长度。长度可以是 1 和 255 之间的任一值。(从 MySQL 3.23 之后,CHAR 的长度可以是 0 到 255。)当 CHAR 值被存储时,他们被用空格在右边填补到指定长度。当 CHAR 值被检索时,尾部的空格被截除。

VARCHAR 列的值是变长的字符串。你可以声明一个 VARCHAR 列在 1 到 255, 就像对 CHAR 列一样。然而,与 CHAR 相反的,VARCHAR 值只以所需的字符数存储,另加一个字节存储记录的长度。值并不被填补;相反的,当被存储时,尾部的空格被截除。(这个截除空格方式不同于 ANSI SQL 规约。)

如果将一个超过列最大长度的值赋给一个 CHARVARCHAR 列,该值将截断以适合它。

下表通过在 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 列上检索值的尾部空格会被截除。

CHARVARCHAR 列值以省略字母大小写的方式进行排序和比较,除非在表建立时 BINARY 属性被指定。BINARY 属性意味着,该列值根据 MySQL 服务器正在运行的机器的 ASCII 表顺序进行字母大小写敏感的方式排序和比较。BINARY 并不影响该列如何被存储和检索。

BINARY 属性是有粘性的。这就意味着,如果一个被标记为 BINARY 的列被用于一个表达式中,整个表达式将作为一个 BINARY 值被比较。

在表创建时,MySQL 可能会隐式地改变一个 CHARVARCHAR 列的类型。查看章节 6.5.3.1 隐式的列定义变化

6.2.3.2 BLOBTEXT 类型

一个 BLOB 是一个可以保存一可变数量的数据的二进制大对象。四个 BLOB 类型(TINYBLOBBLOBMEDIUMBLOBLONGBLOB)之间的不同仅仅在于他们能保存值的最大长度不一致。查看章节 6.2.6 列类型存储需求

四个 TEXT 类型(TINYTEXTTEXTMEDIUMTEXTLONGTEXT)对应与四个 BLOB 类型,并且有相同的最大长度和存储需求。在 BLOBTEXT 类型之间的唯一差别就是,对 BLOB 值是以字母大小写敏感的方式进行排序和比较的,而对 TEXT 值以忽略字母大小写方式进行排序和比较。换句话说,TEXT 是一个忽略字母大小写的 BLOB

如果将一个超过列类型最大长度的值赋给一个 BLOBTEXT 列,该值将被截断以适应它。

在大多数方面,可以将一个 TEXT 列看作是一个你所希望大 VARCHAR 列。同样的,BLOB 列可以看作是一个 VARCHAR BINARY 列。差别就在于:

MyODBCLONGVARBINARY 定义 BLOB 值,以 LONGVARCHAR 定义 TEXT 值。

因为 BLOBTEXT 值可以非常地长,在使用它们时可能会遇到某些限制:

注意,每个 BLOBTEXT 值在内部由一个独立分配的对象表示。这与其它所有的列类型不一样,当表被打开时,它们被按每列分配一次存储。

6.2.3.3 ENUM 类型

ENUM 是一个字符串对象,其值通常选自一个允许值列表中,该列表在表创建时的列规格说明中被明确地列举。

在下列某些情况下,值也可以是空串("") 或 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 为列选择正确的类型

为了更有效地使用存储空间,在任何情况下均尝试使用最精确的类型。例如,如果一个整数列被用于在 199999 之间的值,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 个成员)

VARCHARBLOBTEXT 类型是变长的类型,其存储需求取决于列值的实际长度(上表中以 L 表示),而不是取决于类型的最大可能尺寸。例如,一个 VARCHAR(10) 列可以保存最大长度为 10 个字符的字符串。实际存储需求为字符串长度 (L),再加上 1 个字节用于记录该字符串的长度。对于字符串 'abcd'L 为 4,它的存储需求为 5 字节。

BLOBTEXT 类型需要 1、2、3 或 4 字节记录列值的长度,这取决于该类型的最大可能长度。查看章节 6.2.3.2 BLOBTEXT 类型

如果一个表包含任何变长类型的列类型,记录格式也将是变长的。注意,当一个表被创建时,在某种情况下,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 字节。每个 BLOBTEXT 列只占用相对于这个尺寸中的 5-9 个字节。