目录
1.2 整数类型(精确值)-Integer、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT
2.5 TIMESTAMP和DATETIME的自动初始化和更新
1.数字数据类型
1.1 数字数据类型语法
对于整数数据类型,M表示最小显示宽度。最大显示宽度为255。显示宽度与类型可以存储的值范围无关,如第13.1.6节“数字类型属性”所述。
对于浮点和定点数据类型,M是可以存储的位数总数。
从MySQL 8.0.17开始,整数数据类型不赞成使用display width属性;您应该期望在MySQL的未来版本中删除对它的支持。
如果为数字列指定ZEROFILL,MySQL会自动将UNSIGNED属性添加到该列。
从MySQL 8.0.17开始,ZEROFILL属性不适用于数字数据类型;您应该期望在MySQL的未来版本中删除对它的支持。考虑使用另一种方法来产生此属性的效果。例如,应用程序可以使用LPAD()函数将数字归零至所需宽度,也可以将格式化后的数字存储在CHAR列中。
允许UNSIGNED属性的数字数据类型也允许SIGNED。但是,这些数据类型默认情况下是签名的,因此signed属性没有任何作用。
从MySQL 8.0.17开始,对于FLOAT、DOUBLE和DECIMAL(以及任何同义词)类型的列,不赞成使用UNSIGNED属性;您应该期望在MySQL的未来版本中删除对它的支持。请考虑对此类列使用简单的CHECK约束。
SERIAL是BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的别名。
整数列定义中的SERIAL DEFAULT VALUE是NOT NULL AUTO_INCREMENT UNIQUE的别名。
BIT[(M)]
位值类型。M表示每个值的位数,从1到64。如果省略M,则默认值为1。
TINYINT[(M)][UNSIGNED][ZEROFILL]
一个非常小的整数。带符号的范围是-128到127。无符号范围为0到255。
BOOL, BOOLEAN
这些类型是TINYINT(1)的同义词。零值被认为是错误的。非零值被认为是真的:
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 |
+--------------------------------+
最后两个语句显示所显示的结果,因为2既不等于1也不等于0。
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到9223372036864775807。
无符号范围为0到18446744073709551615。
SERIAL 是BIGINT (无符号 非空 自增 唯一)的别名。
关于BIGINT列,您应该注意一些事项:
1.所有运算都是使用有符号的BIGINT或DOUBLE值完成的,因此除了使用位函数外,不应使用大于9223372036854775807(63位)的无符号大整数!如果您这样做,结果中的一些最后数字可能是错误的,因为在将BIGINT值转换为DOUBLE时出现舍入错误。
MySQL可以在以下情况下处理BIGINT:
2.您可以通过使用字符串将一个精确的整数值存储在BIGINT列中。在这种情况下,MySQL执行字符串到数字的转换,不涉及中间的双精度表示。
3.当两个操作数都是整数值时,-、+和*运算符使用BIGINT算术运算。这意味着,如果将两个大整数(或返回整数的函数的结果)相乘,当结果大于9223372036854775807时,可能会得到意外结果。
DECIMAL[(M[,D])][无符号][零填充]
一个压缩的“精确”定点数。
M是总位数(精度),D是小数点后的位数(小数位数)。小数点和(对于负数)-号不计入M。
如果D为0,则值没有小数点或小数部分。
DECIMAL的最大位数(M)为65。支持的最大小数位数(D)为30。
如果省略D,则默认值为0。如果省略M,则默认值为10。
(DECIMAL文本的长度也有限制;请参阅“表达式处理”。)
如果指定了UNSIGNED,则不允许使用负值。
从MySQL 8.0.17开始,DECIMAL类型的列(以及任何同义词)不推荐使用UNSIGNED属性;
预计在MySQL的未来版本中删除对它的支持。请考虑对此类列使用简单的CHECK约束。
所有具有DECIMAL列的基本计算(+、-、*、/)都以65位的精度完成。
DEC[(M[,D])] [UNSIGNED] [ZEROFILL], NUMERIC[(M[,D])] [UNSIGNED] [ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]
这些类型是DECIMAL的同义词。FIXED同义词可用于与其他数据库系统兼容。
FLOAT[(M,D)] [无符号][零填充]
一个小的(单精度)浮点数。
允许值
这些是基于IEEE标准的理论限制。实际范围可能会稍小,具体取决于您的硬件或操作系统。
M是总位数,D是小数点后的位数。
如果省略M和D,则将值存储到硬件允许的极限。
单精度浮点数精确到小数点后7位左右。
FLOAT(M,D)是一个非标准的MySQL扩展。
从MySQL 8.0.17开始,该语法已被弃用,在未来版本的MySQL中删除对它的支持。
如果指定了UNSIGNED,则不允许使用负值。
从MySQL 8.0.17开始,对于类型为FLOAT(以及任何同义词)的列,UNSIGNED属性是不推荐使用的,将在未来版本的MySQL中删除对它的支持。请考虑对此类列使用简单的CHECK约束。
使用FLOAT可能会给您带来一些意想不到的问题,因为MySQL中的所有计算都是以双精度完成的。
FLOAT(p) [无符号][零填充]
浮点数。
p表示以位为单位的精度,但MySQL仅使用此值来确定结果数据类型是使用FLOAT还是DOUBLE。
如果p在0到24之间,则数据类型变为FLOAT,没有M或D值。
如果p在25到53之间,则数据类型变为DOUBLE,没有M或D值。
结果列的范围与本节前面描述的单精度FLOAT或双精度double数据类型的范围相同。
如果指定了UNSIGNED,则不允许使用负值。
从MySQL 8.0.17开始,对于类型为FLOAT(以及任何同义词)的列,UNSIGNED属性是不推荐使用的,在未来版本的MySQL中删除对它的支持。请考虑对此类列使用简单的CHECK约束。
提供FLOAT(p)语法是为了与ODBC兼容。
DOUBLE[(M,D)] [无符号][零填充]
一个正常大小(双精度)的浮点数。
允许值
这些是基于IEEE标准的理论限制。实际范围可能会稍小,具体取决于您的硬件或操作系统。
M是总位数,D是小数点后的位数。如果省略M和D,则将值存储到硬件允许的极限。双精度浮点数精确到小数点后约15位。
DOUBLE(M,D)是一个非标准的MySQL扩展。
从MySQL 8.0.17开始,此语法已被弃用,在MySQL的未来版本中删除对它的支持。
如果指定了UNSIGNED,则不允许使用负值。
从MySQL 8.0.17开始,对于DOUBLE(和任何同义词)类型的列,不赞成使用UNSIGNED属性,您应该期待在未来版本的MySQL中删除对它的支持。请考虑对此类列使用简单的CHECK约束。
DOUBLE PRECISION[(M,D)] [无符号][零填充], REAL[(M,D)] [无符号][零填充]
这些类型是DOUBLE的同义词。
异常:如果启用了REAL_AS_FLOAT SQL模式,REAL是FLOAT的同义词,而不是DOUBLE。
1.2 整数类型(精确值)-Integer、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT
MySQL支持SQL标准整数类型integer(或INT)和SMALLINT。
作为标准的扩展,MySQL还支持整数类型TINYINT、MEDIUMINT和BIGINT。
下表显示了每种整数类型所需的存储空间和范围。
类型 | 占用空间(Bytes) | 最小值 (有符号) | 最小值 (无符号) | 最大值 (有符号) | 最大值 (无符号) |
---|---|---|---|---|---|
TINYINT | 1 | -128 | 0 | 127 | 255 |
SMALLINT | 2 | -32768 | 0 | 32767 | 65535 |
MEDIUMINT | 3 | -8388608 | 0 | 8388607 | 16777215 |
INT | 4 | -2147483648 | 0 | 2147483647 | 4294967295 |
BIGINT | 8 | -263 | 0 | 263-1 | 264-1 |
1.3 定点类型(精确值)-DECIMAL,NUMERIC
DECIMAL和NUMERIC类型存储精确的数字数据值。当精确精度很重要时,例如货币数据时,会使用这些类型。
在MySQL中,NUMERIC被实现为DECIMAL,因此以下关于DECIMAL的注释同样适用于NUMERIC。
MySQL以二进制格式存储DECIMAL值。参见“精确数学”。
在DECIMAL列声明中,可以(通常)指定精度和小数位数。例如
salary DECIMAL(5,2)
在本例中,5表示精度,2表示小数位数。
精度表示存储的有效位数,小数位数表示小数点后可以存储的位数。
标准SQL要求DECIMAL(5,2)能够存储任何具有五位数字和两位小数的值,因此可以存储在salary列中的值范围为-999.99到999.99。
在标准SQL中,语法DECIMAL(M)等效于DECIMAL的(M,0)。
类似地,语法DECIMAL等效于DECIMAL(M,0),其中允许实现来决定M的值。MySQL支持这两种形式的DECIMAL语法。M的默认值为10。
如果小数位数为0,则DECIMAL值不包含小数点或小数部分。
DECIMAL的最大位数为65,但给定DECIMAL列的实际范围可能受到给定列的精度或小数位数的限制。当为此类列分配的值的小数点后位数超过指定小数位数所允许的位数时,该值将转换为该小数位数。(精确的行为是特定于操作系统的,但通常效果是截断到允许的位数。)
1.4 浮点类型(近似值)-FLOAT、DOUBLE
FLOAT和DOUBLE类型表示近似的数字数据值。
MySQL使用四个字节表示单精度值,使用八个字节表示双精度值。
对于FLOAT,SQL标准允许在括号中的关键字FLOAT(即FLOAT(p))后面的位中指定可选的精度(但不包括指数范围)。
MySQL也支持这个可选的精度规范,但FLOAT(p)中的精度值仅用于确定存储大小。
MySQL允许使用非标准语法:FLOAT(M,D)或REAL(M,D)或DOUBLE PRECISION(M,德)。
这里,(M,D)意味着总共可以存储多达M个数字的值,其中D个数字可以在小数点之后。
例如,定义为FLOAT(7,4)的列显示为-999.9999。
MySQL在存储值时执行四舍五入,因此如果将999.00009插入FLOAT(7,4)列,则近似结果为999.0001。
从MySQL 8.0.17开始,不推荐使用非标准的FLOAT(M,D)和DOUBLE(M,D)语法
在未来版本的MySQL中删除对它的支持。
由于浮点值是近似值,而不是作为精确值存储,因此在比较中试图将其视为精确值可能会导致问题。
它们还受到平台或实现依赖性的影响。有关更多信息,请参阅“浮点值问题”。
为了最大限度地实现可移植性,需要存储近似数字数据值的代码应该使用FLOAT或DOUBLE PRECISION,不指定精度或位数。
1.5 位值类型-Bit
BIT数据类型用于存储位值。一种类型的BIT(M)使得能够存储M比特值。M的范围可以从1到64。
要指定位值,可以使用b'value'表示法。
value是使用0和1编写的二进制值。例如,b'111'和b'10000000'分别表示7和128。
参见“位值文字”。
如果将一个值分配给长度小于M位的BIT(M)列,则该值将在左侧填充零。
例如,将b'101'的值分配给BIT(6)列实际上与分配b'000101'相同。
NDB集群。给定NDB表中使用的所有BIT列的最大组合大小不得超过4096位。
1.6 数字类型属性
MySQL支持一个扩展,可以选择在类型的基本关键字后面的括号中指定整数数据类型的显示宽度。
例如,INT(4)指定显示宽度为四位数的INT。
应用程序可以使用此可选的显示宽度来显示宽度小于为列指定的宽度的整数值,方法是用空格对其进行左填充。(也就是说,这个宽度存在于与结果集一起返回的元数据中。是否使用取决于应用程序。)
显示宽度不限制可以存储在列中的值的范围。它也不会阻止比列显示宽度更宽的值正确显示。
例如,指定为SMALLINT(3)的列通常具有-32768到32767的SMALLINT范围,
并且超出三位数允许范围的值将使用三位数以上的数字完整显示。
与可选(非标准)ZEROFILL属性一起使用时,默认的空格填充将替换为零。
例如,对于声明为INT(4)ZEROFILL的列,值5检索为0005。
从MySQL 8.0.17开始,数字数据类型不推荐使用ZEROFILL属性,整数数据类型也不推荐使用显示宽度属性。
在MySQL的未来版本中删除对ZEROFILL和整数数据类型的显示宽度的支持。
考虑使用其他方法来产生这些属性的效果。
例如,应用程序可以使用LPAD()函数将数字归零至所需宽度,也可以将格式化后的数字存储在CHAR列中。
所有整数类型都可以具有可选(非标准)的UNSIGNED属性。
无符号类型可以用于只允许列中的非负数,或者当您需要该列的较大数值上限时。
例如,如果INT列为UNSIGNED,则该列的范围大小相同,但其端点向上移动,从-2147483648和2147483647移动到0和4294967295。
浮点和定点类型也可以是UNSIGNED。
与整数类型一样,此属性可防止负值存储在列中。与整数类型不同,列值的上限范围保持不变。
从MySQL 8.0.17开始,对于类型为FLOAT、DOUBLE和DECIMAL(以及任何同义词)的列,不推荐使用UNSIGNED属性,在MySQL的未来版本中删除对它的支持。请考虑对此类列使用简单的CHECK约束。
如果为数字列指定ZEROFILL,MySQL会自动添加UNSIGNED属性。
整数或浮点数据类型可以具有AUTO_INCREMENT属性。
在索引AUTO_INCREMENT列中插入NULL值时,该列将设置为下一个序列值。通常这是值+1,其中值是表中当前列的最大值。(AUTO_INCREMENT序列以1开头。)
除非启用了NO_AUTO_VALUE_ON_ZERO SQL模式,否则将0存储到AUTO_INCREMENT列与存储NULL具有相同的效果。
插入NULL以生成AUTO_INCREMENT值需要将列声明为NOT NULL。如果列被声明为NULL,则插入NULL将存储NULL。在AUTO_INCREMENT列中插入任何其他值时,该列将被设置为该值,并重置序列,以便下一个自动生成的值按顺序从插入的值开始。
AUTO_INCREMENT列不支持负值。
CHECK约束不能引用具有AUTO_INCREMENT属性的列,也不能将AUTO_INCREMENT属性添加到CHECK约束中使用的现有列。
从MySQL 8.0.17开始,不推荐对FLOAT和DOUBLE列使用AUTO_INCREMENT支持;
它在MySQL的未来版本中将被删除。考虑从这些列中删除AUTO_INCREMENT属性,或者将它们转换为整数类型。
1.7 超出范围和溢出处理
当MySQL在列数据类型允许范围之外的数字列中存储值时,结果取决于当时有效的SQL模式:
假设表t1具有以下定义:
CREATE TABLE t1 (i1 TINYINT, i2 TINYINT UNSIGNED);
启用严格SQL模式后,会出现超出范围的错误:
mysql> SET sql_mode = 'TRADITIONAL';
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
ERROR 1264 (22003): Out of range value for column 'i1' at row 1
mysql> SELECT * FROM t1;
Empty set (0.00 sec)
在未启用严格SQL模式的情况下,会发生带有警告的剪辑:
mysql> SET sql_mode = '';
mysql> INSERT INTO t1 (i1, i2) VALUES(256, 256);
mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------+
| Warning | 1264 | Out of range value for column 'i1' at row 1 |
| Warning | 1264 | Out of range value for column 'i2' at row 1 |
+---------+------+---------------------------------------------+
mysql> SELECT * FROM t1;
+------+------+
| i1 | i2 |
+------+------+
| 127 | 255 |
+------+------+
如果未启用严格SQL模式,则由于剪切而发生的列分配转换将报告为ALTER TABLE、LOAD DATA、UPDATE和多行INSERT语句的警告。
在严格模式下,这些语句会失败,并且不会插入或更改部分或全部值,这取决于表是否为事务表以及其他因素。
数值表达式求值过程中溢出导致错误。例如,最大的有符号BIGINT值为9223372036854775807,因此以下表达式会产生错误:
mysql> SELECT 9223372036854775807 + 1;
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)'
在这种情况下,要使操作成功,请将值转换为无符号;
mysql> SELECT CAST(9223372036854775807 AS UNSIGNED) + 1;
+-------------------------------------------+
| CAST(9223372036854775807 AS UNSIGNED) + 1 |
+-------------------------------------------+
| 9223372036854775808 |
+-------------------------------------------+
是否发生溢出取决于操作数的范围,因此处理前面表达式的另一种方法是使用精确值算术,因为DECIMAL值的范围比整数大:
mysql> SELECT 9223372036854775807.0 + 1;
+---------------------------+
| 9223372036854775807.0 + 1 |
+---------------------------+
| 9223372036854775808.0 |
+---------------------------+
默认情况下,整数值之间的相减(其中一个为UNSIGNED类型)会产生无符号结果。如果结果本来是负的,则会产生一个错误:
mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)'
如果启用了NO_UNSIGNED_SUBTRACTION SQL模式,则结果为负数:
mysql> SET sql_mode = 'NO_UNSIGNED_SUBTRACTION';
mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
| -1 |
+-------------------------+
如果此操作的结果用于更新UNSIGNED整数列,则将结果剪裁为列类型的最大值,如果启用了NO_UNSIGNED_SUBTRACTION,则将其剪裁为0。如果启用了严格SQL模式,则会发生错误,并且列保持不变。
2.日期和时间数据类型
2.1 日期和时间数据类型语法
用于表示时间值的日期和时间数据类型有date、time、DATETIME、TIMESTAMP和YEAR。
对于DATE和DATETIME范围的描述,“supported”表示尽管早期的值可能有效,但不能保证。
MySQL允许TIME、DATETIME和TIMESTAMP值使用小数秒,精度高达微秒(6位数)。要定义包含小数秒部分的列,请使用语法type_name(fsp),其中type_name是TIME、DATETIME或TIMESTAMP,fsp是小数秒精度。例如
CREATE TABLE t1 (t TIME(3), dt DATETIME(6), ts TIMESTAMP(0));
fsp值(如果给定)必须在0到6的范围内。值为0表示不存在小数部分。如果忽略,默认精度为0。(为了与以前的MySQL版本兼容,这与标准SQL默认值6不同。)
表中的任何TIMESTAMP或DATETIME列都可以具有自动初始化和更新属性;请参阅第13.2.5节“TIMESTAMP和DATETIME的自动初始化和更新”。
DATE
DATETIME[(fsp)]
TIMESTAMP[(fsp)]
TIME[(fsp)]
YEAR[(4)]
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;
2.2 DATE、DATETIME和TIMESTAMP类型
DATE、DATETIME和TIMESTAMP类型是相关的。本节介绍了它们的特点、相似之处以及不同之处。MySQL以多种格式识别DATE、DATETIME和TIMESTAMP值,如第11.1.3节“日期和时间文字”所述。对于DATE和DATETIME范围的描述,“supported”表示尽管早期的值可能有效,但不能保证。
DATE类型用于有日期部分但没有时间部分的值。MySQL检索并显示“YYYY-MM-DD”格式的DATE值。支持的范围为“1000-01-01”到“9999-12-31”。
DATETIME类型用于同时包含日期和时间部分的值。MySQL检索并显示“YYYY-MM-DD hh:MM:ss”格式的DATETIME值。支持的范围为“1000-01-01 00:00:00”到“9999-12-31 23:59:59”。
TIMESTAMP数据类型用于同时包含日期和时间部分的值。TIMESTAMP的范围为协调世界时1970-01-01 00:00:01'到协调世界时2038-01-19 03:14:07'。
DATETIME或TIMESTAMP值可以包括小数秒部分,精度高达微秒(6位数)。特别是,插入DATETIME或TIMESTAMP列的值中的任何小数部分都将被存储,而不是丢弃。包括小数部分后,这些值的格式为“YYYY-MM-DD hh:MM:ss[.fraction]”,DATETIME值的范围为“1000-01-01 00:00:00.000000000”到“9999-12-31 23:59:59.499999”,TIMESTAMP值的范围是“1970-01-01 00:00:01.00000000”和“2038-01-19 03:14:07.499999”。小数部分应始终与其余时间相隔一个小数点;没有识别出其他小数秒分隔符。有关MySQL中分数秒支持的信息,请参阅第13.2.6节“时间值中的分数秒”。
TIMESTAMP和DATETIME数据类型提供对当前日期和时间的自动初始化和更新。有关更多信息,请参阅第13.2.5节“TIMESTAMP和DATETIME的自动初始化和更新”。
MySQL将TIMESTAMP值从当前时区转换为UTC进行存储,并将其从UTC转换回当前时区进行检索。(其他类型(如DATETIME)不会发生这种情况。)默认情况下,每个连接的当前时区是服务器的时间。可以根据每个连接设置时区。只要时区设置保持不变,您就会得到与存储的值相同的值。如果存储TIMESTAMP值,然后更改时区并检索该值,则检索到的值与存储的值不同。发生这种情况的原因是没有将同一时区用于两个方向的转换。当前时区可用作time_zone系统变量的值。有关更多信息,请参阅第7.1.15节“MySQL Server时区支持”。
在MySQL 8.0.19及更高版本中,可以在表中插入TIMESTAMP或DATETIME值时指定时区偏移量。有关更多信息和示例,请参见第11.1.3节“日期和时间文字”。
如果SQL模式允许进行此转换,则无效的DATE、DATETIME或TIMESTAMP值将转换为适当类型的“零”值(“000-00-00”或“0000-00-00 00:00:00”)。精确的行为取决于是否启用了严格SQL模式和NO_ZERO_DATE SQL模式中的任何一个;请参阅第7.1.11节“服务器SQL模式”。
在MySQL 8.0.22及更高版本中,当使用带有AT TIME ZONE运算符的CAST()检索TIMESTAMP值时,可以将其转换为UTC DATETIME值,如下所示:
mysql> SELECT col,
> CAST(col AT TIME ZONE INTERVAL '+00:00' AS DATETIME) AS ut
> FROM ts ORDER BY id;
+---------------------+---------------------+
| col | ut |
+---------------------+---------------------+
| 2020-01-01 10:10:10 | 2020-01-01 15:10:10 |
| 2019-12-31 23:40:10 | 2020-01-01 04:40:10 |
| 2020-01-01 13:10:10 | 2020-01-01 18:10:10 |
| 2020-01-01 10:10:10 | 2020-01-01 15:10:10 |
| 2020-01-01 04:40:10 | 2020-01-01 09:40:10 |
| 2020-01-01 18:10:10 | 2020-01-01 23:10:10 |
+---------------------+---------------------+
有关语法和其他示例的完整信息,请参阅CAST()函数的描述。
请注意MySQL中日期值解释的某些属性:
另见2.9“日期中的2位数年份”。
2.3 TIME类型
MySQL以“hh:mm:ss”格式检索并显示TIME值(对于较大的小时值,则以“hhhh:mm:ss”格式)。TIME值的范围可能从“838:59:59”到“838:59:39”。小时部分可能很大,因为TIME类型不仅可以用于表示一天中的时间(必须小于24小时),还可以用于表示经过的时间或两个事件之间的时间间隔(可能远大于24小时,甚至为负数)。
MySQL可以识别几种格式的TIME值,其中一些格式可以包括精度高达微秒(6位数)的小数秒部分。参见第11.1.3节“日期和时间文字”。有关MySQL中分数秒支持的信息,请参阅第13.2.6节“时间值中的分数秒”。特别是,插入TIME列的值中的任何小数部分都将被存储,而不是丢弃。包括小数部分后,TIME值的范围为“-838:59:59.000000”到“838:59:59.00000”。
为TIME列指定缩写值时要小心。MySQL将带冒号的缩写TIME值解释为一天中的时间。也就是说,“11:12”的意思是“11:12:00”,而不是“00:11:12”。MySQL解释不带冒号的缩写值,假设最右边的两位数字表示秒(即经过的时间,而不是一天中的时间)。例如,您可能认为“1112”和1112的意思是“11:12:00”(11点后12分钟),但MySQL将它们解释为“00:11:12”(11分12秒)。类似地,“12”和“12”被解释为“00:00: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:000”还是无效。
要对无效的TIME值进行更严格的处理,请启用严格的SQL模式以导致错误的发生。
2.4 YEAR类型
YEAR类型是用于表示年份值的1字节类型。它可以声明为隐式显示宽度为4个字符的YEAR,也可以等效为显式显示宽度的YEAR(4)。
MySQL以YYYY格式显示YEAR值,范围为1901到2155,以及0000。
YEAR接受各种格式的输入值:
如果未启用严格的SQL模式,MySQL会将无效的YEAR值转换为0000。在严格的SQL模式中,试图插入无效的YEAR值会产生错误。
另见“日期中的2位数年份”。
2.5 TIMESTAMP和DATETIME的自动初始化和更新
TIMESTAMP和DATETIME列可以自动初始化并更新为当前日期和时间(即当前时间戳)。
对于表中的任何TIMESTAMP或DATETIME列,您可以将当前时间戳指定为默认值、自动更新值或两者都指定:
此外,如果explicit_defaults_for_timestamp系统变量被禁用,则可以通过为任何timestamp(但不是DATETIME)列分配NULL值来将其初始化或更新为当前日期和时间,除非它已使用NULL属性定义为允许NULL值。
要指定自动属性,请在列定义中使用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_IMESTAMP子句。条款的顺序无关紧要。如果列定义中同时存在这两种情况,则可以先出现其中一种情况。CURRENT_TIMESTAMP的任何同义词都与CURRENT_IMESTAMP具有相同的含义。它们是CURRENT_TIMESTAMP()、NOW()、LOCALTIME、LOCALTIME()、OCALTIMESTAMP和LOCALTIMESTAMP()。
DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_IMESTAMP的使用特定于TIMESTAMP与DATETIME。DEFAULT子句也可用于指定常量(非自动)默认值(例如,DEFAULT 0或DEFAULT“2000-01-01 00:00:00”)。
TIMESTAMP或DATETIME列定义可以为默认值和自动更新值指定当前时间戳,也可以为其中一个而不是另一个,或者两者都不指定。不同的列可以具有不同的自动特性组合。以下规则描述了各种可能性:
使用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_IMESTAMP时,列的默认值具有当前时间戳,并自动更新为当前时间戳。
CREATE TABLE t1 (
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
如果有DEFAULT子句,但没有ON UPDATE CURRENT_TIMESTAMP子句,则该列具有给定的默认值,并且不会自动更新到当前时间戳。
默认值取决于default子句指定的是CURRENT_TIMESTAMP还是常数值。对于CURRENT_TIMESTAMP,默认值为当前时间戳。
CREATE TABLE t1 (
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
dt DATETIME DEFAULT CURRENT_TIMESTAMP
);
对于常量,默认值为给定值。在这种情况下,该列根本没有自动属性。
CREATE TABLE t1 (
ts TIMESTAMP DEFAULT 0,
dt DATETIME DEFAULT 0
);
使用ON UPDATE CURRENT_TIMESTAMP子句和常量DEFAULT子句,列将自动更新为当前时间戳,并具有给定的常量默认值。
CREATE TABLE t1 (
ts TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP,
dt DATETIME DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP
);
如果有ON UPDATE CURRENT_TIMESTAMP子句,但没有DEFAULT子句,则列会自动更新为当前时间戳,但其默认值没有当前时间戳。
这种情况下的默认值取决于类型。TIMESTAMP的默认值为0,除非使用NULL属性进行定义,在这种情况下,默认值为NULL。
CREATE TABLE t1 (
ts1 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- default 0
ts2 TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP -- default NULL
);
除非使用NOT NULL属性定义,否则DATETIME的默认值为NULL,在这种情况下,默认值为0。
CREATE TABLE t1 (
dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP, -- default NULL
dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0
);
TIMESTAMP和DATETIME列没有自动属性,除非它们是显式指定的,但以下情况除外:如果explicit_defaults_for_TIMESTAMP系统变量被禁用,则第一个TIMESTAMP列同时具有DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_IMESTAMP(如果两者都未显式指定)。要抑制第一个TIMESTAMP列的自动属性,请使用以下策略之一:
考虑以下表格定义:
CREATE TABLE t1 (
ts1 TIMESTAMP DEFAULT 0,
ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t2 (
ts1 TIMESTAMP NULL,
ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
CREATE TABLE t3 (
ts1 TIMESTAMP NULL DEFAULT 0,
ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP);
这些表具有以下属性:
如果TIMESTAMP或DATETIME列定义的任何位置都包含显式小数秒精度值,则必须在整个列定义中使用相同的值。这是允许的:
CREATE TABLE t1 (
ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
);
这是不允许的:
CREATE TABLE t1 (
ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(3)
);
2.5.1 TIMESTAMP初始化和NULL属性
如果explicit_defaults_for_timestamp系统变量被禁用,则timestamp列默认情况下为NOT NULL,不能包含NULL值,并且分配NULL将分配当前时间戳。要允许TIMESTAMP列包含NULL,请使用NULL属性显式声明它。在这种情况下,默认值也变为NULL,除非用指定不同默认值的default子句重写。DEFAULT NULL可用于显式指定NULL作为默认值。(对于未使用NULL属性声明的TIMESTAMP列,DEFAULT NULL无效。)如果TIMESTAMP列允许NULL值,则分配NULL会将其设置为NULL,而不是当前时间戳。
下表包含几个允许NULL值的TIMESTAMP列:
CREATE TABLE t
(
ts1 TIMESTAMP NULL DEFAULT NULL,
ts2 TIMESTAMP NULL DEFAULT 0,
ts3 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
);
允许NULL值的TIMESTAMP列在插入时不采用当前时间戳,除非符合以下条件之一:
换句话说,定义为允许NULL值的TIMESTAMP列只有在其定义包括DEFAULT CURRENT_TIMESTAMP时才会自动初始化:
CREATE TABLE t (ts TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP);
如果TIMESTAMP列允许NULL值,但其定义不包括DEFAULT CURRENT_TIMESTAMP,则必须显式插入与当前日期和时间相对应的值。假设表t1和t2具有以下定义:
CREATE TABLE t1 (ts TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00');
CREATE TABLE t2 (ts TIMESTAMP NULL DEFAULT NULL);
要在插入时将任一表中的TIMESTAMP列设置为当前时间戳,请显式为其指定该值。例如
INSERT INTO t2 VALUES (CURRENT_TIMESTAMP);
INSERT INTO t1 VALUES (NOW());
如果启用了explicit_defaults_for_timestamp系统变量,则timestamp列只有在使用NULL属性声明时才允许NULL值。此外,TIMESTAMP列不允许分配NULL来分配当前时间戳,无论是用NULL还是not NULL属性声明的。要分配当前时间戳,请将该列设置为current_timestamp或类似NOW()的同义词。
2.6 时间值的小数秒
MySQL支持分数秒的TIME、DATETIME和TIMESTAMP值,精度高达微秒(6位数):
要定义包含小数秒部分的列,请使用语法type_name(fsp),其中type_name是TIME、DATETIME或TIMESTAMP,fsp是小数秒精度。例如
CREATE TABLE t1 (t TIME(3), dt DATETIME(6));
fsp值(如果给定)必须在0到6的范围内。值为0表示不存在小数部分。如果忽略,默认精度为0。(为了与以前的MySQL版本兼容,这与标准SQL默认值6不同。)
将带有小数秒部分的TIME、DATE或TIMESTAMP值插入到相同类型但小数位数较少的列中会导致舍入。考虑如下创建和填充的表:
CREATE TABLE fractest( c1 TIME(2), c2 DATETIME(2), c3 TIMESTAMP(2) );
INSERT INTO fractest VALUES
('17:51:04.777', '2018-09-08 17:51:04.777', '2018-09-08 17:51:04.777');
将时间值插入到表格中,并四舍五入:
mysql> SELECT * FROM fractest;
+-------------+------------------------+------------------------+
| c1 | c2 | c3 |
+-------------+------------------------+------------------------+
| 17:51:04.78 | 2018-09-08 17:51:04.78 | 2018-09-08 17:51:04.78 |
+-------------+------------------------+------------------------+
当出现这种舍入时,不会给出任何警告或错误。此行为遵循SQL标准。
要插入带有截断的值,请启用TIME_TRUNCATE_FRACTIONAL SQL模式:
SET @@sql_mode = sys.list_add(@@sql_mode, 'TIME_TRUNCATE_FRACTIONAL');
在启用该SQL模式的情况下,插入时间值时会进行截断:
mysql> SELECT * FROM fractest;
+-------------+------------------------+------------------------+
| c1 | c2 | c3 |
+-------------+------------------------+------------------------+
| 17:51:04.77 | 2018-09-08 17:51:04.77 | 2018-09-08 17:51:04.77 |
+-------------+------------------------+------------------------+
2.7 MySQL使用什么Calendar?
MySQL使用的是一种被称为Gregorian 的公历。
每一个从Julian 改为公历的国家都必须在改历期间至少放弃十天。要了解这是如何运作的,请考虑1582年10月,当时发生了第一次从Julian到Gregorian的转换。
Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
10月4日至10月15日之间没有日期。这种不连续性被称为割接。割接之前的任何日期均为Julian历,割接之后的任何日期都为Gregorian历。割接期间的日期是不存在的。
日历应用于未实际使用的日期,称为proretic。因此,如果我们假设从来没有切换,格里高利规则总是占主导地位,那么我们就有了一个预期的格里高利日历。这是MySQL所使用的,也是标准SQL所要求的。因此,必须调整存储为MySQL DATE或DATETIME值的转换之前的日期,以补偿差异。重要的是要认识到,并非所有国家都在同一时间发生割接,而且割接发生得越晚,损失的天数就越多。例如,在英国,它发生在1752年,9月2日星期三之后是9月14日星期四。俄罗斯一直沿用Julian历,直到1918年,在这一过程中损失了13天,根据Gregorian,人们通常称之为“十月革命”的事件发生在11月。
2.8 日期和时间类型之间的转换
在某种程度上,您可以将一个值从一种时态类型转换为另一种。然而,信息的价值可能会发生一些变化或丢失。在所有情况下,时态类型之间的转换都受结果类型的有效值范围的限制。例如,尽管DATE、DATETIME和TIMESTAMP值都可以使用同一组格式指定,但这些类型的值范围并不相同。TIMESTAMP值不能早于1970 UTC或晚于'2038-01-19 03:14:07'UTC。这意味着诸如“1968-01-01”这样的日期,虽然作为date或DATETIME值有效,但作为TIMESTAMP值无效,并被转换为0。
DATE值的转换:
DATETIME和TIMESTAMP值的转换:
对于将TIME值转换为其他时态类型,CURRENT_DATE()的值用于日期部分。TIME被解释为经过的时间(而不是一天中的时间),并添加到日期中。这意味着,如果时间值在“00:00:00”到“23:59:59”的范围之外,则结果的日期部分与当前日期不同。
假设当前日期为“2012-01-01”。“12:00:00”、“24:00:00”和“-12:00:0”的TIME值转换为DATETIME或TIMESTAMP值时,将分别产生“2012-01-01 12:00:00’、“2012-01-02 00:00:00”和“2011-12-31 12:00:00‘。
TIME到DATE的转换类似,但从结果中丢弃了时间部分:分别为“2012-01-01”、“2012-01-02”和“2011-12-31”。
显式转换可用于覆盖隐式转换。例如,在比较DATE和DATETIME值时,通过添加“00:00:00”的时间部分,将DATE值强制为DATETIME类型。要通过忽略DATETIME值的时间部分来执行比较,请按以下方式使用CAST()函数:
date_col = CAST(datetime_col AS DATE)
将TIME和DATETIME值转换为数字形式(例如,通过添加+0)取决于该值是否包含小数秒部分。当N为0(或省略)时,TIME(N)或DATETIME(N)转换为整数,当N大于0时,转换为具有N个十进制数字的DECIMAL值:
mysql> SELECT CURTIME(), CURTIME()+0, CURTIME(3)+0;
+-----------+-------------+--------------+
| CURTIME() | CURTIME()+0 | CURTIME(3)+0 |
+-----------+-------------+--------------+
| 09:28:00 | 92800 | 92800.887 |
+-----------+-------------+--------------+
mysql> SELECT NOW(), NOW()+0, NOW(3)+0;
+---------------------+----------------+--------------------+
| NOW() | NOW()+0 | NOW(3)+0 |
+---------------------+----------------+--------------------+
| 2012-08-15 09:28:00 | 20120815092800 | 20120815092800.889 |
2.9 日期中的2位数年份
年份为2位数的日期值不明确,因为世纪未知。这些值必须解释为4位数的形式,因为MySQL在内部使用4位数存储年份。
对于DATETIME、DATE和TIMESTAMP类型,MySQL使用以下规则解释使用不明确年份值指定的日期:
对于YEAR,规则是相同的,但有一个例外:在YEAR中插入数字00会导致0000而不是2000。要为YEAR指定零并将其解释为2000,请将其指定为字符串“0”或“00”。
请记住,这些规则只是试探性的,可以对数据值的含义提供合理的猜测。如果MySQL使用的规则没有产生所需的值,则必须提供包含4位年份值的明确输入。
ORDER BY对年份为2位数的YEAR值进行适当排序。
一些函数,如MIN()和MAX(),将YEAR转换为数字。这意味着年份为2位数的值不能正常使用这些函数。这种情况下的修复方法是将YEAR转换为4位数的年份格式。
未完待续。。。