本节描述使用 2 位YEAR(2)
数据类型时可能出现的问题,并提供有关将现有
YEAR(2)
列转换为 4 位年份值列的信息,这些列可以声明为
YEAR
具有 4 个字符的隐式显示宽度,或等效YEAR(4)
于显式显示宽度。
尽管
YEAR
/YEAR(4)
和弃用YEAR(2)
类型的内部值范围相同(1901
to2155
和0000
),但显示宽度
YEAR(2)
使该类型本质上不明确,因为显示的值仅指示内部值的最后两位数字并省略了世纪数字。结果在某些情况下可能会丢失信息。出于这个原因,请避免
YEAR(2)
在您的应用程序中使用并
在需要年值数据类型的任何地方使用YEAR
/ 。YEAR(4)
请注意,在某些时候需要转换,因为支持
YEAR
显示值不是 4 的数据类型,最值得注意
YEAR(2)
的是,从 MySQL 5.6.6 开始减少,并在 MySQL 5.7 中完全删除。
数据类型的问题YEAR(2)
包括显示值的歧义,以及当值被转储和重新加载或转换为字符串时可能丢失的信息。
显示
YEAR(2)
的值可能不明确。最多三个YEAR(2)
具有不同内部值的值可能具有相同的显示值,如以下示例所示:mysql> CREATE TABLE t (y2 YEAR(2), y4 YEAR); Query OK, 0 rows affected, 1 warning (0.01 sec) mysql> INSERT INTO t (y2) VALUES(1912),(2012),(2112); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql> UPDATE t SET y4 = y2; Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0 mysql> SELECT * FROM t; +------+------+ | y2 | y4 | +------+------+ | 12 | 1912 | | 12 | 2012 | | 12 | 2112 | +------+------+ 3 rows in set (0.00 sec)
如果您使用mysqldump转储在前面示例中创建的表,则转储文件
y2
使用相同的 2 位数字表示法 ( ) 表示所有值12
。如果您从转储文件中重新加载表,则所有结果行都具有内部值2012
和显示值12
,从而失去它们之间的区别。将 2 位或 4 位
YEAR
数据值转换为字符串形式使用数据类型显示宽度。假设一个YEAR(2)
列和一个YEAR
/YEAR(4)
列都包含该值1970
。将每一列分配给一个字符串会分别产生'70'
或的值'1970'
。也就是说,从YEAR(2)
到字符串的转换会丢失信息。当插入表 中的列时, 超出范围的值
1970
将 被错误存储。例如,插入结果显示值为 ,但内部值为。2069
YEAR(2)
CSV
2211
11
2011
要避免这些问题,请使用 4 位
YEAR
或
YEAR(4)
数据类型而不是 2 位YEAR(2)
数据类型。有关迁移策略的建议出现在本节的后面。
从 MySQL 5.6.6 开始,对以下
YEAR(2)
内容的支持减少了:
YEAR(2)
新表的列定义被转换(带有ER_INVALID_YEAR_COLUMN_LENGTH
警告)为 4 位数字的YEAR
列:mysql> CREATE TABLE t1 (y YEAR(2)); Query OK, 0 rows affected, 1 warning (0.04 sec) mysql> SHOW WARNINGS\G *************************** 1. row *************************** Level: Warning Code: 1818 Message: YEAR(2) column type is deprecated. Creating YEAR(4) column instead. 1 row in set (0.00 sec) mysql> SHOW CREATE TABLE t1\G *************************** 1. row *************************** Table: t1 Create Table: CREATE TABLE `t1` ( `y` year(4) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec)
YEAR(2)
现有表中的列与旧版本的 MySQL 一样保留YEAR(2)
并在查询中处理。但是,一些程序或语句会自动将YEAR(2)
列转换为 4 位数字的YEAR
列:ALTER TABLE
导致表重建的语句。REPAIR TABLE
(CHECK TABLE
建议您使用,如果它找到包含YEAR(2)
列的表)。使用mysqldump转储并重新加载转储文件。与前面三项执行的转换不同,转储和重新加载有可能更改数据值。
MySQL 升级通常至少涉及最后两项中的一项。但是,关于
YEAR(2)
, mysql_upgrade优于 mysqldump,如前所述,后者可以更改数据值。
要将 2 位列转换YEAR(2)
为 4 位列YEAR
,您可以随时手动执行此操作而无需升级。或者,您可以升级到支持减少的 MySQL 版本YEAR(2)
(MySQL 5.6.6 或更高版本),然后让 MySQL
YEAR(2)
自动转换列。在后一种情况下,避免通过转储和重新加载数据来升级,因为这会更改数据值。此外,如果您使用复制,则必须考虑升级注意事项。
要手动
将 2 位数字YEAR(2)
列转换为 4 位数字,请使用或
。假设一个表有这样的定义:
YEAR
ALTER TABLE
REPAIR TABLE
t1
CREATE TABLE t1 (ycol YEAR(2) NOT NULL DEFAULT '70');
修改列使用ALTER TABLE
如下:
ALTER TABLE t1 FORCE;
该ALTER TABLE
语句在不更改
YEAR(2)
值的情况下转换表。如果服务器是复制源,则该ALTER
TABLE
语句复制到副本并在每个副本上更改相应的表。
另一种迁移方法是执行二进制升级:在不转储和重新加载数据的情况下就地升级 MySQL 5.6.6 或更高版本。然后运行
mysql_upgrade,它用于
REPAIR TABLE
将 2
位列转换YEAR(2)
为 4
位列YEAR
而不更改数据值。如果服务器是复制源,则
REPAIR TABLE
语句复制到副本并在每个副本上进行相应的表更改,除非您
使用该
选项
调用mysql_upgrade 。--skip-write-binlog
升级到复制服务器通常涉及将副本升级到更新版本的 MySQL,然后升级源。例如,如果源和副本都运行 MySQL 5.5,则典型的升级顺序包括将副本升级到 5.6,然后将源升级到 5.6。关于YEAR(2)
MySQL 5.6.6 的不同处理,升级顺序导致了一个问题:假设副本已经升级但源还没有升级。然后在源上创建一个包含 2 位数字
YEAR(2)
列的表会生成一个包含 4 位数字的表
YEAR
副本上的列。因此,如果您使用基于语句的复制,则以下操作在源和副本上会产生不同的结果:
为避免此类问题,请使用以下策略之一:
使用基于行的复制而不是基于语句的复制。
在升级之前将
YEAR(2)
源上的 所有 2 位列修改为 4 位列。YEAR
(使用ALTER TABLE
,如前所述。)这使得正常升级(首先是副本,然后是源)成为可能,而不会在源和副本之间引入任何YEAR(2)
差异YEAR(4)
。
应避免一种迁移方法:不要使用mysqldump转储数据并在升级后重新加载转储文件。YEAR(2)
如前所述,
这有可能改变
价值。
从 2 位数字
YEAR(2)
列迁移到 4 位数字
YEAR
列还应包括检查应用程序代码以了解在以下情况下行为发生变化的可能性: