mysql数据类型详解
MySQL 支持大量的列类型,它们可以被分为 3 类:数字类型、日期和时间类型以及字符串(字符)类型。这个章节首先给出可用类型的概述,并且总结各类型所需的存储需求,然后提供各类型中的类型范畴更详细的描述。概述有意地简化了。更详细的说明应该参考特写列类型的附加信息,例如你能为其指定值的允许格式。
MySQL 支持的列类型在下面列出。下列代码字母用于描述中:
M指出最大的显示尺寸。最大的显示尺寸长度为 255。D适用于浮点类型。指出跟随在十进制小数点后的数字数量。最大可能值为 30,但不应大于M-2。方括号 (“[”and“]”) 指定可选的类型修饰部份。
注意,如果为一个列指定了ZEROFILL,MySQL 将自动为这个列添加UNSIGNED属性。
警告:你应该知道当在两个整数类型值中使用减法时,如有一个为UNSIGNED类型,那么结果也是无符号的。查看章节6.3.5 Cast 函数。
TINYINT[(M)] [UNSIGNED] [ZEROFILL]-128到127。无符号的范围是0到255。BITBOOL它们是TINYINT(1)的同义词。
SMALLINT[(M)] [UNSIGNED] [ZEROFILL]一个小整数。有符号的范围是-32768到32767。无符号的范围是0到65535。
MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]一个中等大小的整数。有符号的范围是-8388608到8388607。无符号的范围是0到16777215。
INT[(M)] [UNSIGNED] [ZEROFILL]一个正常大小的整数。有符号的范围是-2147483648到2147483647。无符号的范围是0到4294967295。
INTEGER[(M)] [UNSIGNED] [ZEROFILL]INT的同义词。
BIGINT[(M)] [UNSIGNED] [ZEROFILL]一个大的整数。有符号的范围是-9223372036854775808到9223372036854775807。无符号的范围是0到18446744073709551615。
你应该知道的有关BIGINT列的一些事情:
- BIGINT或DOUBLE值来完成的,因此你不应该使用大于9223372036854775807(63 bits) 的无符号大整数,除了位函数之外!如果你这样做了,结果中的某些大数字可能会出错,因为将BIGINT转换成DOUBLE时产生了舍入错误。MySQL 4.0 在下列情况下可以处理BIGINT:
- 通常你可以在一个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 解决没有匹配行的问题。
FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]一个小的(单精度) 浮点数字。允许的值是-3.402823466E+38到-1.175494351E-38、0和1.175494351E-38到3.402823466E+38。如果UNSIGNED被指定,负值是不允许的。M是显示宽度,D是小数位数。FLOAT没有参数或有X<= 24 的FLOAT(X)代表一个单精度的浮点数字。
DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]一个正常大小的(双精度)浮上数字。允许的值是-1.7976931348623157E+308到-2.2250738585072014E-308、0和2.2250738585072014E-308到1.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列,实际的范围可以被所选择的M和D限制。如果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.2DATETIME、DATE和TIMESTAMP类型。
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.2DATETIME、DATE和TIMESTAMP类型。
TIMESTAMP[(M)]一个时间戳。范围是'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类型。TIME一个时间。范围是'-838:59:59'到'838:59:59'。MySQL 以'HH:MM:SS'格式显示TIME值,但是允许你使用字符串或数字来给TIME列赋值。查看章节6.2.2.3TIME类型。YEAR[(2|4)]一个 2 或 4 位数字格式的年(缺省为 4 位)。允许的值是1901到2155、0000(4 位年格式) 以及使用 2 位格式的 1970-2069 (70-69)。MySQL 以YYYY格式显示YEAR值,但是允许你使用字符串或数字来给YEAR列赋值。(YEAR类型在 MySQL 3.22 之前不支持。) 查看章节6.2.2.4YEAR类型。
[NATIONAL] CHAR(M) [BINARY]一个定长的字符串,当存储时,总是以空格填满右边到指定的长度。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这是CHAR(1)的同义词。
[NATIONAL] VARCHAR(M) [BINARY]一个变长的字符串。注意:尾部的空格在存储时将会被删除(这与 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类型。
TINYBLOBTINYTEXT一个BLOB或TEXT列,最大长度为 255 (2^8 - 1) 个字符。查看章节6.5.3.1 隐式的列定义变化。查看章节6.2.3.2BLOB和TEXT类型。
BLOBTEXT一个BLOB或TEXT列,最大长度为 65535 (2^16 - 1) 个字符。查看章节6.5.3.1 隐式的列定义变化。查看章节6.2.3.2BLOB和TEXT类型。
MEDIUMBLOBMEDIUMTEXT一个BLOB或TEXT列,最大长度为 16777215 (2^24 - 1) 个字符。查看章节6.5.3.1 隐式的列定义变化。查看章节6.2.3.2BLOB和TEXT类型。
LONGBLOBLONGTEXT一个BLOB或TEXT列,最大长度为 4294967295 (2^32 - 1) 个字符。查看章节6.5.3.1 隐式的列定义变化。注意,由于服务器/客户端的协议以及 MyISAM 表通常有一个 16M 每通信包/表行的限制,你仍然不能使用这个类型的整个范围。查看章节6.2.3.2BLOB和TEXT类型。ENUM('value1','value2',...)一个枚举类型。一个仅能有一个值的字符串对象,这个值选自值列'value1'、'value2'、...、NULL或特殊的""出错值。一个ENUM列可以有最大 65535 不同的值。查看章节6.2.3.3ENUM类型。SET('value1','value2',...)一个集合。一个能有零个或更多个值的字符串对象,其中每个值必须选自值列'value1'、'value2'、...。一个SET列可以有最大 64 个成员。查看章节6.2.3.4SET类型。
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列被赋与一个大小超过指定(或缺省)的precisionandscale的限止范围时,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 |
日期和时间类型有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,这更易于书写。
- 在MyODBC2.50.12 和以上的版本中,“零”值的日期和时间值通过MyODBC将被自动转换成NULL,因为 ODBC 不能够处理这样的值。
MySQL 自身是 Y2K 安全的(查看章节1.2.5 2000 年兼容性),但是呈交给 MySQL 的值可能并不是。任何一个包含 2 位年份的值是存在二义性的,因为世纪值是未知的。这样的值必须被解释为 4 位格式,因为 MySQL 内部使用四位存储年份。
对于DATETIME、DATE、TIMESTAMP和YEAR类型,MySQL 使用下列规则解释存在二义性的年份值:
- 在范围00-69内的年值被转换为2000-2069。
- 在范围Y70-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)) 的方法。
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格式。不是这些长度之一的数字通过在值前补零到最接近的长度后解释。
'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。
MySQL 以'HH:MM:SS'格式(或对大的小时值时使用'HHH:MM:SS'格式)检索和显示TIME值。