PingKai Logo下载

MODIFY COLUMN

ALTER TABLE .. MODIFY COLUMN 语句用于修改已有表上的列,包括列的数据类型和属性。若要同时重命名,可改用 CHANGE COLUMN 语句。

从 v5.1.0 版本起,TiDB 开始支持 Reorg 类型变更,包括但不限于:

  • VARCHAR 转换为 BIGINT
  • DECIMAL 精度修改
  • VARCHAR(10)VARCHAR(5) 的长度压缩

语法图

AlterTableStmt
ALTER IGNORE TABLE TableName ModifyColumnSpec ,
ModifyColumnSpec
MODIFY ColumnKeywordOpt IF EXISTS ColumnName ColumnType ColumnOption FIRST AFTER ColumnName
ColumnType
NumericType StringType DateAndTimeType SERIAL
ColumnOption
NOT NULL AUTO_INCREMENT PRIMARY KEY CLUSTERED NONCLUSTERED UNIQUE KEY DEFAULT NowSymOptionFraction SignedLiteral NextValueForSequence SERIAL DEFAULT VALUE ON UPDATE NowSymOptionFraction COMMENT stringLit CONSTRAINT Identifier CHECK ( Expression ) NOT ENFORCED NULL GENERATED ALWAYS AS ( Expression ) VIRTUAL STORED REFERENCES TableName ( IndexPartSpecificationList ) Match OnDeleteUpdateOpt COLLATE CollationName COLUMN_FORMAT ColumnFormat STORAGE StorageMedia AUTO_RANDOM ( LengthNum )
ColumnName
Identifier . Identifier . Identifier

示例

Meta-Only Change

CREATE TABLE t1 (id int not null primary key AUTO_INCREMENT, col1 INT);
Query OK, 0 rows affected (0.11 sec)
INSERT INTO t1 (col1) VALUES (1),(2),(3),(4),(5);
Query OK, 5 rows affected (0.02 sec)
Records: 5  Duplicates: 0  Warnings: 0
ALTER TABLE t1 MODIFY col1 BIGINT;
Query OK, 0 rows affected (0.09 sec)
SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `col1` bigint DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=30001
1 row in set (0.00 sec)

Reorg-Data Change

CREATE TABLE t1 (id int not null primary key AUTO_INCREMENT, col1 INT);
Query OK, 0 rows affected (0.11 sec)
INSERT INTO t1 (col1) VALUES (12345),(67890);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
ALTER TABLE t1 MODIFY col1 VARCHAR(5);
Query OK, 0 rows affected (2.52 sec)
SHOW CREATE TABLE t1\G
*************************** 1. row ***************************
       Table: t1
CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `col1` varchar(5) DEFAULT NULL,
  PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=30001
1 row in set (0.00 sec)

注意:

修改非聚簇主键成员列的类型

TiDB 支持使用 MODIFY COLUMN 修改 NONCLUSTERED PRIMARY KEY 成员列的数据类型,包括单列非聚簇主键和复合非聚簇主键中的成员列。该操作属于 Reorg-Data 类型的在线 DDL。TiDB 会对表中已有数据执行类型转换,并重组受影响的主键索引;如果该列同时被其他二级索引引用,相关索引也会同步重组。

例如:

CREATE TABLE t_pk (
    id DECIMAL(20,0) NOT NULL,
    tenant_key VARCHAR(10),
    PRIMARY KEY (id) NONCLUSTERED
);
INSERT INTO t_pk VALUES (1, 'a'), (2, 'b');
ALTER TABLE t_pk MODIFY COLUMN id BIGINT NOT NULL;
Query OK, 0 rows affected

复合非聚簇主键中的成员列也支持该操作:

CREATE TABLE t_composite_pk (
    tenant_id BIGINT NOT NULL,
    id DECIMAL(20,0) NOT NULL,
    PRIMARY KEY (tenant_id, id) NONCLUSTERED
);
ALTER TABLE t_composite_pk MODIFY COLUMN id BIGINT NOT NULL;

执行该操作时,TiDB 会检查已有数据是否可以安全转换到目标类型、转换后的主键是否仍保持唯一、转换后的索引长度是否满足限制等。如果类型转换不合法或转换后产生重复主键,DDL 会失败并回滚,不会保留部分转换结果。

该能力仅适用于非聚簇主键。对于 CLUSTERED PRIMARY KEY,如果列类型变更会影响 row handle、行键编码或数据物理组织,TiDB 仍不支持执行。

为已有列添加 AUTO_INCREMENT 属性

TiDB 支持使用 MODIFY COLUMN 为已有的符合条件的整型列添加 AUTO_INCREMENT 属性。典型场景是已有表已经使用整型列作为主键或唯一键,后续需要补充自增 ID 分配能力。

例如:

CREATE TABLE t_auto_inc (
    id BIGINT NOT NULL PRIMARY KEY,
    source_id BIGINT
);
INSERT INTO t_auto_inc VALUES (1, 100), (2, 200);

ALTER TABLE t_auto_inc MODIFY COLUMN id BIGINT NOT NULL AUTO_INCREMENT;
INSERT INTO t_auto_inc (source_id) VALUES (300);
SELECT * FROM t_auto_inc ORDER BY id;
+----+-----------+
| id | source_id |
+----+-----------+
|  1 |       100 |
|  2 |       200 |
|  3 |       300 |
+----+-----------+
3 rows in set (0.00 sec)

执行该操作时,TiDB 会检查目标列是否为支持 AUTO_INCREMENT 的整型类型、是否满足非空和索引要求、表中是否已经存在其他 AUTO_INCREMENT 列,以及已有数据是否可以安全用于初始化后续自增 ID 的分配起点。如果已有值达到类型上限、目标列不满足索引约束,或者与 AUTO_RANDOM 等其他 ID 分配能力冲突,DDL 会失败并回滚。

MySQL 兼容性

  • TiDB 支持修改 NONCLUSTERED PRIMARY KEY 成员列上需要 Reorg-Data 的类型。对于 CLUSTERED PRIMARY KEY,如果列类型变更会影响 row handle 或数据物理组织,则仍不支持。例如:

    CREATE TABLE t (a DECIMAL(20,0) NOT NULL, PRIMARY KEY (a) NONCLUSTERED);
    ALTER TABLE t MODIFY COLUMN a BIGINT NOT NULL;
    Query OK, 0 rows affected
    CREATE TABLE t (a int primary key clustered);
    ALTER TABLE t MODIFY COLUMN a BIGINT NOT NULL;
    ERROR 8200 (HY000): Unsupported modify column: can't modify column in clustered primary key
    CREATE TABLE t (a int primary key nonclustered);
    ALTER TABLE t MODIFY COLUMN a bigint;
    Query OK, 0 rows affected (0.01 sec)
  • 支持使用 MODIFY COLUMN 为已有的符合条件的整型列添加 AUTO_INCREMENT 属性。目标列需要满足 AUTO_INCREMENT 的类型、NOT NULL、索引和唯一性要求,且表中不能已经存在其他 AUTO_INCREMENT 列。不支持使用 ADD COLUMN 添加带有 AUTO_INCREMENT 属性的新列。

  • 不支持修改生成列的类型。例如:

    CREATE TABLE t (a INT, b INT as (a+1));
    ALTER TABLE t MODIFY COLUMN b VARCHAR(10);
    ERROR 8200 (HY000): Unsupported modify column: column is generated
  • 不支持修改分区表上的列类型。例如:

    CREATE TABLE t (c1 INT, c2 INT, c3 INT) partition by range columns(c1) ( partition p0 values less than (10), partition p1 values less than (maxvalue));
    ALTER TABLE t MODIFY COLUMN c1 DATETIME;
    ERROR 8200 (HY000): Unsupported modify column: table is partition table
  • 不支持部分数据类型(例如,部分 TIME 类型、BIT、SET、ENUM、JSON 等)向某些类型的变更,因为 TiDB 的 CAST 函数与 MySQL 的行为有一些兼容性问题。例如:

    CREATE TABLE t (a DECIMAL(13, 7));
    ALTER TABLE t MODIFY COLUMN a DATETIME;
    ERROR 8200 (HY000): Unsupported modify column: change from original type decimal(13,7) to datetime is currently unsupported yet

另请参阅