目录
[1.1 数字数据类型语法](#1.1 数字数据类型语法)
[1.2 整数类型(精确值)-Integer、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT](#1.2 整数类型(精确值)-Integer、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT)
[1.3 定点类型(精确值)-DECIMAL,NUMERIC](#1.3 定点类型(精确值)-DECIMAL,NUMERIC)
[1.4 浮点类型(近似值)-FLOAT、DOUBLE](#1.4 浮点类型(近似值)-FLOAT、DOUBLE)
[1.5 位值类型-Bit](#1.5 位值类型-Bit)
[1.6 数字类型属性](#1.6 数字类型属性)
[1.7 超出范围和溢出处理](#1.7 超出范围和溢出处理)
[2.1 日期和时间数据类型语法](#2.1 日期和时间数据类型语法)
[2.2 DATE、DATETIME和TIMESTAMP类型](#2.2 DATE、DATETIME和TIMESTAMP类型)
[2.3 TIME类型](#2.3 TIME类型)
[2.4 YEAR类型](#2.4 YEAR类型)
[2.5 TIMESTAMP和DATETIME的自动初始化和更新](#2.5 TIMESTAMP和DATETIME的自动初始化和更新)
[2.5.1 TIMESTAMP初始化和NULL属性](#2.5.1 TIMESTAMP初始化和NULL属性)
[2.6 时间值的小数秒](#2.6 时间值的小数秒)
[2.7 MySQL使用什么Calendar?](#2.7 MySQL使用什么Calendar?)
[2.8 日期和时间类型之间的转换](#2.8 日期和时间类型之间的转换)
[2.9 日期中的2位数年份](#2.9 日期中的2位数年份)
[3.1 字符串数据类型语法](#3.1 字符串数据类型语法)
[3.2 CHAR和VARCHAR类型](#3.2 CHAR和VARCHAR类型)
[3.3 BINARY和VARBINARY类型](#3.3 BINARY和VARBINARY类型)
[3.4 BLOB和TEXT类型](#3.4 BLOB和TEXT类型)
[3.5 ENUM类型](#3.5 ENUM类型)
[3.6 SET类型](#3.6 SET类型)
[4.1 空间数据类型](#4.1 空间数据类型)
[4.2 OpenGIS几何模型](#4.2 OpenGIS几何模型)
[4.3 支持的空间数据格式](#4.3 支持的空间数据格式)
[4.4 几何的良好形式性与有效性](#4.4 几何的良好形式性与有效性)
[4.5 空间参考系统支持](#4.5 空间参考系统支持)
[4.6 创建空间列](#4.6 创建空间列)
[4.7 填充空间列](#4.7 填充空间列)
[4.8 获取空间数据](#4.8 获取空间数据)
[4.9 优化空间分析](#4.9 优化空间分析)
[4.10 创建空间索引](#4.10 创建空间索引)
[4.11 使用空间索引](#4.11 使用空间索引)
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的别名。
警告:
如果在整数值之间使用减法,其中一个为UNSIGNED类型,则除非启用NO_UNSIGNED_SUBTRACTION SQL模式,否则结果为无符号。
请参阅"强制转换函数和运算符"。
BIT[(M)]
位值类型。M表示每个值的位数,从1到64。如果省略M,则默认值为1。
TINYINT[(M)][UNSIGNED][ZEROFILL]
一个非常小的整数。带符号的范围是-128到127。无符号范围为0到255。
BOOL, BOOLEAN
这些类型是TINYINT(1)的同义词。零值被认为是错误的。非零值被认为是真的:
sql
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的别名,如下所示:
sql
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:
在BIGINT列中使用整数存储大的无符号值时。
在MIN(col_name)或MAX(col_name)中,其中col_name表示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)] [无符号][零填充]
一个小的(单精度)浮点数。
允许值
-3402823466E+38 至**-1.175494351E-38**
0
1.175494351E-38 至3.402823466E+38。
这些是基于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)] [无符号][零填充]
一个正常大小(双精度)的浮点数。
允许值
1.7976931348623157E+308至-2.2250738585072014E-308
0
以及2.22507385850714E-308至1.7976931484623157E+308。
这些是基于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列声明中,可以(通常)指定精度和小数位数。例如
sql
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)中的精度值仅用于确定存储大小。
从0到23的精度会产生一个4字节的单精度FLOAT列。
从24到53的精度产生一个8字节的双精度double列。
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。
注意:
对于表达式或UNION查询中涉及的列,ZEROFILL属性将被忽略。
如果将大于显示宽度的值存储在具有ZEROFILL属性的整数列中,则MySQL为某些复杂联接生成临时表时可能会遇到问题。在这些情况下,MySQL假设数据值适合列显示宽度。
从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模式:
如果启用了严格的SQL模式,MySQL会根据SQL标准拒绝超出范围的值并返回错误,并且插入失败。
如果没有启用限制模式 ,MySQL会将值剪辑到列数据类型范围的适当端点,并存储结果值。当一个超出范围的值被分配给一个整数列时,MySQL存储表示列数据类型范围的相应端点的值。
当为浮点或定点列分配的值超过指定(或默认)精度和小数位数所暗示的范围时,MySQL将存储表示该范围的相应端点的值。
假设表t1具有以下定义:
sql
CREATE TABLE t1 (i1 TINYINT, i2 TINYINT UNSIGNED);
启用严格SQL模式后,会出现超出范围的错误:
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模式的情况下,会发生带有警告的剪辑:
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语句的警告。
在严格模式下,这些语句会失败,并且不会插入或更改部分或全部值,这取决于表是否为事务表以及其他因素。
有关详细信息,请参阅"服务器SQL模式"。
数值表达式求值过程中溢出导致错误。例如,最大的有符号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
支持的范围为"1000-01-01"到"9999-12-31"。
MySQL以"YYYY-MM-DD"格式显示DATE值,但允许使用字符串或数字将值分配给DATE列。
DATETIME[(fsp)]
日期和时间的组合。
支持的范围为"1000-01-01 00:00:00.00000000"到"9999-12-31 23:59:59.499999"。
MySQL以"YYYY-MM-DD hh:MM:ss[.fracte]"格式显示DATETIME值,但允许使用字符串或数字将值分配给DATETIME列。
可以给出0到6范围内的可选fsp值,以指定小数秒精度。值为0表示不存在小数部分。
如果忽略,默认精度为0。
DATETIME列的自动初始化和更新到当前日期和时间可以使用DEFAULT 和ON UPDATE列定义子句指定
如"TIMESTAMP和DATETIME的自动初始化与更新"所述。
TIMESTAMP[(fsp)]
范围为"1970-01-01 00:00:01.000000"UTC到"2038-01-19 03:14:07.499999"UTC。TIMESTAMP值存储为自epoch('1970-01-01 00:00:00'UTC)以来的秒数。
TIMESTAMP不能表示值"1970-01-01 00:00:00",
因为这相当于从epoch开始的0秒,并且值0保留用于表示"0000-00-00 00:00:00"("零"TIMESTAMP值)。
可以给出0到6范围内的可选fsp值,以指定小数秒精度。值为0表示不存在小数部分。如果忽略,默认精度为0。
服务器处理TIMESTAMP定义的方式取决于explicit_defaults_for_timestamp系统变量的值(请参阅"服务器系统变量")。
如果启用explicit_defaults_for_timestamp
则不会自动将DEFAULT CURRENT_TIMESTAMP或ON UPDATE CURRENT_TIMESTAMP属性分配给任何timestamp列。
它们必须明确地包含在列定义中。此外,任何未明确声明为NOT NULL的TIMESTAMP都允许NULL值。
如果explicit_defaults_for_timestamp被禁用,则服务器将按如下方式处理timestamp:
除非另有规定,否则表中的第一个TIMESTAMP列将被定义为在未显式指定值的情况下自动设置为最近修改的日期和时间。
这使得TIMESTAMP可用于记录INSERT或UPDATE操作的时间戳。
您也可以通过为任何TIMESTAMP列分配NULL值来将其设置为当前日期和时间,除非它已使用NULL属性定义为允许NULL值。
可以使用DEFAULT current_TIMESTAMP和ON UPDATE current_IMESTAMP列定义子句指定自动初始化和更新到当前日期和时间。
默认情况下,第一个TIMESTAMP列具有这些属性,如前所述。
但是,表中的任何TIMESTAMP列都可以定义为具有这些属性。
TIME[(fsp)]
一次。范围为"-838:59:59.000000"到"838:59:59.00000"。MySQL以"hh:mm:ss[.fract]"格式显示TIME值,但允许使用字符串或数字将值分配给TIME列。
可以给出0到6范围内的可选fsp值,以指定小数秒精度。值为0表示不存在小数部分。如果忽略,默认精度为0。
YEAR[(4)]
四位数格式的年份。MySQL以YYYY格式显示YEAR值,但允许使用字符串或数字将值分配给YEAR列。值显示为1901到2155或0000。
有关YEAR显示格式和输入值解释的更多信息,请参阅2.4"YEAR类型"。
注意:从MySQL 8.0.19开始,不推荐使用具有显式显示宽度的YEAR(4)数据类型;
在MySQL的未来版本中删除对它的支持。
相反,使用不带显示宽度的YEAR,其含义相同。
MySQL 8.0不支持旧版本MySQL中允许的2位数YEAR(2)数据类型。
有关转换为4位数YEAR的说明
请参阅MySQL 5.7参考手册中的2位数YEAR(2)限制和迁移到4位数YEAL。
SUM()和AVG()聚合函数不适用于日期值。(它们将值转换为数字,在第一个非数字字符之后丢失所有内容。)要解决此问题,请转换为数字单位,执行聚合操作,然后转换回时间值。示例:
sql
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值,如下所示:
sql
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中日期值解释的某些属性:
MySQL允许对指定为字符串的值使用"宽松"格式,其中任何标点符号都可以用作日期部分或时间部分之间的分隔符。在某些情况下,这种语法可能具有欺骗性。例如,像"10:11:12"这样的值可能看起来像时间值,因为:,但如果在日期上下文中使用,则会被解释为年份"2010-11-12"。值"10:45:15"转换为"0000-00-00",因为"45"不是有效的月份。
日期和时间部分与小数秒部分之间唯一可识别的分隔符是小数点。
服务器要求月份和日期值有效,而不仅仅是分别在1到12和1到31的范围内。禁用严格模式后,无效日期(如"2004-04-31")将转换为"0000-00-00",并生成警告。启用严格模式后,无效日期会产生错误。要允许这样的日期,请启用ALLOW_INVALID_dates。有关详细信息,请参阅第7.1.11节"服务器SQL模式"。
MySQL不接受在天或月列中包含零的TIMESTAMP值或无效日期的值。如果SQL模式允许此值,则此规则的唯一例外是特殊的"零"值"0000-00-00 00:00:00"。精确的行为取决于是否启用了严格SQL模式和NO_ZERO_DATE SQL模式中的任何一个;请参阅第7.1.11节"服务器SQL模式"。包含2位数年份值的日期不明确,因为世纪未知。MySQL使用以下规则解释2位数的年份值:
00-69范围内的年份值变为2000-2069。
70-99范围内的年份值变为1970-1999。
另见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模式以导致错误的发生。
请参阅第"服务器SQL模式"。
2.4 YEAR类型
YEAR类型是用于表示年份值的1字节类型。它可以声明为隐式显示宽度为4个字符的YEAR,也可以等效为显式显示宽度的YEAR(4)。
注意:
从MySQL 8.0.19开始,不赞成使用具有显式显示宽度的YEAR(4)数据类型,在MySQL的未来版本中删除对它的支持。
相反,使用不带显示宽度的YEAR,其含义相同。
MySQL 8.0不支持旧版本MySQL中允许的2位数YEAR(2)数据类型。
有关转换为4位数YEAR的说明,请参阅MySQL 5.7参考手册中的2位数YEAR(2)限制和迁移到4位数YEAL。
MySQL以YYYY格式显示YEAR值,范围为1901到2155,以及0000。
YEAR接受各种格式的输入值:
作为范围为"1901"到"2155"的4位字符串。
作为1901到2155范围内的4位数。
范围为"0"到"99"的1位或2位字符串。MySQL将范围为"0"到"69"和"70"到"99"的值转换为范围为2000到2069和1970到1999的YEAR值。
作为0到99范围内的1位或2位数字。MySQL将介于1到69和70到99之间的值转换为介于2001到2069和1970到1999之间的YEAR值。
插入数字0的结果显示值为0000,内部值为0000。若要插入零并将其解释为2000,请将其指定为字符串"0"或"00"。
作为返回在YEAR上下文中可接受的值的函数的结果,例如NOW()。
如果未启用严格的SQL模式,MySQL会将无效的YEAR值转换为0000。在严格的SQL模式中,试图插入无效的YEAR值会产生错误。
另见"日期中的2位数年份"。
2.5 TIMESTAMP和DATETIME的自动初始化和更新
TIMESTAMP和DATETIME列可以自动初始化并更新为当前日期和时间(即当前时间戳)。
对于表中的任何TIMESTAMP或DATETIME列,您可以将当前时间戳指定为默认值、自动更新值或两者都指定:
对于未为列指定值的插入行,自动初始化的列将设置为当前时间戳。
当行中任何其他列的值从其当前值更改时,自动更新的列会自动更新为当前时间戳。如果所有其他列都设置为其当前值,则自动更新的列保持不变。若要防止自动更新的列在其他列更改时更新,请显式将其设置为当前值。要在其他列不变的情况下更新自动更新的列,请显式地将其设置为应具有的值(例如,将它设置为CURRENT_TIMESTAMP)。
此外,如果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")。
注意:
以下示例使用DEFAULT 0,这是一个默认值,根据启用的是严格SQL模式还是NO_ZERO_DATE SQL模式,它可能会产生警告或错误。
请注意,传统SQL模式包括严格模式和NO_ZERO_DATE。请参阅"服务器SQL模式"。
TIMESTAMP或DATETIME列定义可以为默认值和自动更新值指定当前时间戳,也可以为其中一个而不是另一个,或者两者都不指定。不同的列可以具有不同的自动特性组合。以下规则描述了各种可能性:
使用DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_IMESTAMP时,列的默认值具有当前时间戳,并自动更新为当前时间戳。
sql
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,默认值为当前时间戳。
sql
CREATE TABLE t1 (
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
dt DATETIME DEFAULT CURRENT_TIMESTAMP
);
对于常量,默认值为给定值。在这种情况下,该列根本没有自动属性。
sql
CREATE TABLE t1 (
ts TIMESTAMP DEFAULT 0,
dt DATETIME DEFAULT 0
);
使用ON UPDATE CURRENT_TIMESTAMP子句和常量DEFAULT子句,列将自动更新为当前时间戳,并具有给定的常量默认值。
sql
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列的自动属性,请使用以下策略之一:
启用explicit_defaults_for_timestamp系统变量。在这种情况下,指定自动初始化和更新的DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_IMESTAMP子句可用,但除非明确包含在列定义中,否则不会分配给任何TIMESTAMP列。
或者,如果explicit_defaults_for_timestamp被禁用,请执行以下任一操作:使用指定常量默认值的DEFAULT子句定义列。
指定NULL属性。这也会导致该列允许NULL值,这意味着您无法通过将该列设置为NULL来分配当前时间戳。指定NULL会将列设置为NULL,而不是当前时间戳。要分配当前时间戳,请将该列设置为current_timestamp或类似NOW()的同义词。
考虑以下表格定义:
sql
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列没有自动初始化或更新。
这两个表的不同之处在于ts1列处理NULL值的方式。对于t1,ts1不为NULL,并且为其赋值为NULL会将其设置为当前时间戳。对于t2和t3,ts1允许NULL,并为其赋值NULL将其设置为NULL。
t2和t3的ts1的默认值不同。对于t2,ts1被定义为允许NULL,因此在没有显式default子句的情况下,默认值也是NULL。对于t3,ts1允许NULL,但显式默认值为0。
如果TIMESTAMP或DATETIME列定义的任何位置都包含显式小数秒精度值,则必须在整个列定义中使用相同的值。这是允许的:
sql
CREATE TABLE t1 (
ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
);
这是不允许的:
sql
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列:
sql
CREATE TABLE t
(
ts1 TIMESTAMP NULL DEFAULT NULL,
ts2 TIMESTAMP NULL DEFAULT 0,
ts3 TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP
);
允许NULL值的TIMESTAMP列在插入时不采用当前时间戳,除非符合以下条件之一:
其默认值定义为CURRENT_TIMESTAMP,并且没有为列指定值
CURRENT_TIMESTAMP或其任何同义词(如NOW())显式插入列中
换句话说,定义为允许NULL值的TIMESTAMP列只有在其定义包括DEFAULT CURRENT_TIMESTAMP时才会自动初始化:
sql
CREATE TABLE t (ts TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP);
如果TIMESTAMP列允许NULL值,但其定义不包括DEFAULT CURRENT_TIMESTAMP,则必须显式插入与当前日期和时间相对应的值。假设表t1和t2具有以下定义:
sql
CREATE TABLE t1 (ts TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00');
CREATE TABLE t2 (ts TIMESTAMP NULL DEFAULT NULL);
要在插入时将任一表中的TIMESTAMP列设置为当前时间戳,请显式为其指定该值。例如
sql
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是小数秒精度。例如
sql
CREATE TABLE t1 (t TIME(3), dt DATETIME(6));
fsp值(如果给定)必须在0到6的范围内。值为0表示不存在小数部分。如果忽略,默认精度为0。(为了与以前的MySQL版本兼容,这与标准SQL默认值6不同。)
将带有小数秒部分的TIME、DATE或TIMESTAMP值插入到相同类型但小数位数较少的列中会导致舍入。考虑如下创建和填充的表:
sql
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');
将时间值插入到表格中,并四舍五入:
sql
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模式:
sql
SET @@sql_mode = sys.list_add(@@sql_mode, 'TIME_TRUNCATE_FRACTIONAL');
在启用该SQL模式的情况下,插入时间值时会进行截断:
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 |
+-------------+------------------------+------------------------+
采用临时参数的函数接受具有小数秒的值。时间函数的返回值包括适当的分数秒。例如,不带参数的NOW()返回不带小数部分的当前日期和时间,但使用从0到6的可选参数来指定返回值包括小数秒部分。
时态文字的语法产生时态值:DATE'str'、TIME'str]和TIMESTAMP'str',以及ODBC语法等效项。如果指定,结果值将包括后面的小数秒部分。以前,temporal type关键字被忽略,这些构造生成字符串值。请参阅标准SQL和ODBC日期和时间文字
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值会添加"00:00:00"的时间部分,因为DATE值不包含时间信息。
转换为TIME值没有用处;结果为"00:00:00"。
DATETIME和TIMESTAMP值的转换:
转换为DATE值时会考虑小数秒数,并将时间部分四舍五入。例如,"1999-12-31 23:59:59.499"变为"1999-12/31",而"1999-1231 23:59:59.500"则变为"2000-01-01"。
转换为TIME值将丢弃日期部分,因为TIME类型不包含日期信息。
对于将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()函数:
sql
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使用以下规则解释使用不明确年份值指定的日期:
00-69范围内的年份值变为2000-2069。
70-99范围内的年份值变为1970-1999。
对于YEAR,规则是相同的,但有一个例外:在YEAR中插入数字00会导致0000而不是2000。要为YEAR指定零并将其解释为2000,请将其指定为字符串"0"或"00"。
请记住,这些规则只是试探性的,可以对数据值的含义提供合理的猜测。如果MySQL使用的规则没有产生所需的值,则必须提供包含4位年份值的明确输入。
ORDER BY对年份为2位数的YEAR值进行适当排序。
一些函数,如MIN()和MAX(),将YEAR转换为数字。这意味着年份为2位数的值不能正常使用这些函数。这种情况下的修复方法是将YEAR转换为4位数的年份格式。
未完待续。。。