Documentation Home
MySQL 8.0 参考手册  / 第 11 章数据类型  / 11.2 日期和时间数据类型  /  11.2.5 2 位数 YEAR(2) 限制和迁移到 4 位数 YEAR

11.2.5 2 位数 YEAR(2) 限制和迁移到 4 位数 YEAR

本节描述使用 2 位YEAR(2)数据类型时可能出现的问题,并提供有关将现有 YEAR(2)列转换为 4 位年份值列的信息,这些列可以声明为 YEAR具有 4 个字符的隐式显示宽度,或等效YEAR(4)于显式显示宽度。

尽管 YEAR/YEAR(4) 和弃用YEAR(2)类型的内部值范围相同(1901to21550000),但显示宽度 YEAR(2)使该类型本质上不明确,因为显示的值仅指示内部值的最后两位数字并省略了世纪数字。结果在某些情况下可能会丢失信息。出于这个原因,请避免 YEAR(2)在您的应用程序中使用并 在需要年值数据类型的任何地方使用YEAR/ 。YEAR(4)从 MySQL 5.7.5 开始,YEAR(2)删除了对的支持,现有的 2 位数字YEAR(2) 列必须转换为 4 位数字 YEAR列再次可用。

YEAR(2) 限制

数据类型的问题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将 被错误存储。例如,插入结果显示值为 ,但内部值为。 2069YEAR(2)CSV2211112011

要避免这些问题,请使用 4 位 YEARYEAR(4)数据类型而不是 2 位YEAR(2)数据类型。有关迁移策略的建议出现在本节的后面。

减少/删除 MySQL 5.7 中的 YEAR(2) 支持

在 MySQL 5.7.5 之前,对的支持 YEAR(2)减少了。从 MySQL 5.7.5 开始,对的支持 YEAR(2)被移除。

  • YEAR(2)新表的列定义产生警告或错误:

    • 在 MySQL 5.7.5 之前, 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)
    • 从 MySQL 5.7.5 开始, YEAR(2)新表的列定义会产生 ER_INVALID_YEAR_COLUMN_LENGTH 错误:

      mysql> CREATE TABLE t1 (y YEAR(2));
      ERROR 1818 (HY000): Supports only YEAR or YEAR(4) column.
  • YEAR(2)现有表中的列保持为YEAR(2)

    • 在 MySQL 5.7.5 之前, YEAR(2)与旧版本的 MySQL 一样在查询中处理。

    • 从 MySQL 5.7.5 开始, YEAR(2)查询中的列会产生警告或错误。

  • 几个程序或语句自动将 YEAR(2)列转换为 4 位数字的 YEAR列:

    MySQL 升级通常至少涉及最后两项中的一项。但是,关于 YEAR(2)mysql_upgrade优于 mysqldump,如前所述,后者可以更改数据值。

从 YEAR(2) 迁移到 4 位数 YEAR

要将 2 位列转换YEAR(2) 为 4 位列YEAR ,您可以随时手动执行此操作而无需升级。或者,您可以升级到减少或删除支持的 MySQL 版本 YEAR(2)(MySQL 5.6.6 或更高版本),然后让 MySQLYEAR(2) 自动转换列。在后一种情况下,避免通过转储和重新加载数据来升级,因为这会更改数据值。此外,如果您使用复制,则必须考虑升级注意事项。

要手动 将 2 位数字YEAR(2) 列转换为 4 位数字,请使用或 。假设一个表有这样的定义: YEARALTER TABLEREPAIR TABLEt1

CREATE TABLE t1 (ycol YEAR(2) NOT NULL DEFAULT '70');

修改列使用ALTER TABLE如下:

ALTER TABLE t1 FORCE;

ALTER TABLE语句在不更改 YEAR(2)值的情况下转换表。如果服务器是复制源,则该ALTER TABLE语句复制到副本并在每个副本上更改相应的表。

另一种迁移方法是执行二进制升级:在不转储和重新加载数据的情况下就地升级 MySQL。然后运行​​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副本上的列。因此,如果您使用基于语句的复制,则以下操作在源和副本上会产生不同的结果:

  • 插入数字0. 结果值2000在源上有一个内部值,但0000在副本上。

  • 转换YEAR(2)为字符串。YEAR(2)此操作使用源上但 YEAR(4)副本 上的显示值 。

为避免此类问题, 请在升级前将YEAR(2)源上的所有 2 位列修改为 4位列。YEAR(使用ALTER TABLE,如前所述。)这使得正常升级(首先是副本,然后是源)成为可能,而不会在源和副本之间引入任何 YEAR(2)差异 YEAR(4)

应避免一种迁移方法:不要使用mysqldump转储数据并在升级后重新加载转储文件。YEAR(2)如前所述, 这有可能改变 价值。

从 2 位数字 YEAR(2)列迁移到 4 位数字 YEAR列还应包括检查应用程序代码以了解在以下情况下行为发生变化的可能性:

  • 期望选择一 YEAR列以恰好生成两位数字的代码。

  • 不考虑对 numeric 插入的不同处理的代码: 分别0插入 or 导致 or 的内部值 。 0YEAR(2)YEAR(4)20000000