• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • ALTER TABLE语句

    ALTER TABLE tbl_name
        [alter_specification [, alter_specification] ...]
        [partition_options]
    
    alter_specification:
        table_options
      | ADD [COLUMN] col_name column_definition
            [FIRST | AFTER col_name]
      | ADD [COLUMN] (col_name column_definition,...)
      | ADD {INDEX|KEY} [index_name]
            [index_type] (key_part,...) [index_option] ...
      | ADD {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name]
            (key_part,...) [index_option] ...
      | ADD [CONSTRAINT [symbol]] PRIMARY KEY
            [index_type] (key_part,...)
            [index_option] ...
      | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY]
            [index_name] [index_type] (key_part,...)
            [index_option] ...
      | ADD [CONSTRAINT [symbol]] FOREIGN KEY
            [index_name] (col_name,...)
            reference_definition
      | ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]
      | DROP {CHECK|CONSTRAINT} symbol
      | ALTER {CHECK|CONSTRAINT} symbol [NOT] ENFORCED
      | ALGORITHM [=] {DEFAULT|INSTANT|INPLACE|COPY}
      | ALTER [COLUMN] col_name
            {SET DEFAULT {literal | (expr)} | DROP DEFAULT}
      | ALTER INDEX index_name {VISIBLE | INVISIBLE}
      | CHANGE [COLUMN] old_col_name new_col_name column_definition
            [FIRST|AFTER col_name]
      | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]
      | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
      | {DISABLE|ENABLE} KEYS
      | {DISCARD|IMPORT} TABLESPACE
      | DROP [COLUMN] col_name
      | DROP {INDEX|KEY} index_name
      | DROP PRIMARY KEY
      | DROP FOREIGN KEY fk_symbol
      | FORCE
      | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
      | MODIFY [COLUMN] col_name column_definition
            [FIRST | AFTER col_name]
      | ORDER BY col_name [, col_name] ...
      | RENAME COLUMN old_col_name TO new_col_name
      | RENAME {INDEX|KEY} old_index_name TO new_index_name
      | RENAME [TO|AS] new_tbl_name
      | {WITHOUT|WITH} VALIDATION
    
    partition_options:
        partition_option [partition_option] ...
    
    partition_option:
        ADD PARTITION (partition_definition)
      | DROP PARTITION partition_names
      | DISCARD PARTITION {partition_names | ALL} TABLESPACE
      | IMPORT PARTITION {partition_names | ALL} TABLESPACE
      | TRUNCATE PARTITION {partition_names | ALL}
      | COALESCE PARTITION number
      | REORGANIZE PARTITION partition_names INTO (partition_definitions)
      | EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH|WITHOUT} VALIDATION]
      | ANALYZE PARTITION {partition_names | ALL}
      | CHECK PARTITION {partition_names | ALL}
      | OPTIMIZE PARTITION {partition_names | ALL}
      | REBUILD PARTITION {partition_names | ALL}
      | REPAIR PARTITION {partition_names | ALL}
      | REMOVE PARTITIONING
    
    key_part: {col_name [(length)] | (expr)} [ASC | DESC]
    
    index_type:
        USING {BTREE | HASH}
    
    index_option:
        KEY_BLOCK_SIZE [=] value
      | index_type
      | WITH PARSER parser_name
      | COMMENT 'string'
      | {VISIBLE | INVISIBLE}
    
    table_options:
        table_option [[,] table_option] ...
    
    table_option:
        AUTO_INCREMENT [=] value
      | AVG_ROW_LENGTH [=] value
      | [DEFAULT] CHARACTER SET [=] charset_name
      | CHECKSUM [=] {0 | 1}
      | [DEFAULT] COLLATE [=] collation_name
      | COMMENT [=] 'string'
      | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'}
      | CONNECTION [=] 'connect_string'
      | {DATA|INDEX} DIRECTORY [=] 'absolute path to directory'
      | DELAY_KEY_WRITE [=] {0 | 1}
      | ENCRYPTION [=] {'Y' | 'N'}
      | ENGINE [=] engine_name
      | INSERT_METHOD [=] { NO | FIRST | LAST }
      | KEY_BLOCK_SIZE [=] value
      | MAX_ROWS [=] value
      | MIN_ROWS [=] value
      | PACK_KEYS [=] {0 | 1 | DEFAULT}
      | PASSWORD [=] 'string'
      | ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
      | STATS_AUTO_RECALC [=] {DEFAULT|0|1}
      | STATS_PERSISTENT [=] {DEFAULT|0|1}
      | STATS_SAMPLE_PAGES [=] value
      | TABLESPACE tablespace_name [STORAGE {DISK|MEMORY}]
      | UNION [=] (tbl_name[,tbl_name]...)
    
    partition_options:
        (see CREATE TABLE options)
    

    ALTER TABLE更改表的结构。例如,您可以添加或删除列,创建或销毁索引,更改现有列的类型或重命名列或表本身。您还可以更改特征,例如用于表或表注释的存储引擎。

    • 要使用ALTER TABLE,你需要ALTERCREATEINSERT权限表。重命名表需要ALTERDROP对旧表,ALTERCREATE,和INSERT对新表。
    • 在表名之后,指定要进行的更改。如果没有给出,ALTER TABLE则不执行任何操作。
    • 许多允许的更改的语法类似于该CREATE TABLE语句的子句。column_definition条款使用相同的语法ADDCHANGE作为CREATE TABLE。有关更多信息,请参见“ CREATE TABLE语句”。
    • 该词COLUMN是可选的,并且可以省略,除了RENAME COLUMN(以区分列重命名操作和RENAME表重命名操作)。
    • ADDALTERDROP,和CHANGE条款,允许在一个单一的ALTER TABLE声明中,用逗号隔开。这是对标准SQL的MySQL扩展,每个ALTER TABLE语句仅允许每个子句之一。例如,要在单个语句中删除多个列,请执行以下操作:

      ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;
      
    • 如果存储引擎不支持尝试的ALTER TABLE操作,则可能会产生警告。这样的警告可以用显示SHOW WARNINGS。请参见“ SHOW WARNINGS语句”。有关故障排除的信息ALTER TABLE,请参见第B.4.6.1节“ ALTER TABLE的问题”。
    • 有关生成的列的信息,请参见“ ALTER TABLE和生成的列”。
    • 有关用法示例,请参见“ ALTER TABLE示例”。
    • InnoDB在MySQL 8.0.17和更高版本中,使用key_part规范可以采用形式,支持在JSON列上添加多值索引。有关多值索引的创建和使用以及对多值索引的限制和限制的详细信息,请参阅“多值索引”。(CAST json_path AS type ARRAY)
    • 使用mysql_info()C API函数,您可以找出所复制的行数ALTER TABLE。参见“ mysql_info()”。

    ALTER TABLE语句还有其他几个方面,在本节的以下主题下进行描述:

    • 表格选项
    • 性能和空间要求
    • 并发控制
    • 添加和删除列
    • 重命名,重新定义和重新排序列
    • 主键和索引
    • 外键和其他约束
    • 更改字符集
    • 导入InnoDB表
    • MyISAM表的行顺序
    • 分区选项

    表格选项

    table_options意味着可以在可以使用的一种表选项CREATE TABLE语句,比如ENGINEAUTO_INCREMENTAVG_ROW_LENGTHMAX_ROWSROW_FORMAT,或TABLESPACE

    有关所有表选项的说明,请参见“ CREATE TABLE语句”。但是,ALTER TABLE忽略DATA DIRECTORYINDEX DIRECTORY作为表选项给定时。ALTER TABLE只允许它们作为分区选项,并要求您具有FILE特权。

    通过使用表选项,ALTER TABLE可以方便地更改单个表的特征。例如:

    • 如果t1当前不是InnoDB表,则此语句将其存储引擎更改为InnoDB

      ALTER TABLE t1 ENGINE = InnoDB;
      
      • 有关将表切换到InnoDB存储引擎的注意事项,请参见“将表从MyISAM转换为InnoDB”。
      • 指定ENGINE子句时,ALTER TABLE将重建表。即使表已经具有指定的存储引擎,也是如此。
      • 在现有表上运行会执行“ null ”操作,该操作可用于对表进行碎片整理,如“对表进行碎片整理”中所述。在表上运行执行相同的功能。ALTER TABLE tbl_name ENGINE=INNODBInnoDBALTER TABLEInnoDBALTER TABLE tbl_name FORCEInnoDB
      • ALTER TABLE tbl_name ENGINE=INNODB并使用在线DDL。有关更多信息,请参见“ InnoDB和在线DDL”。ALTER TABLE tbl_name FORCE
      • 尝试更改表的存储引擎的结果受所需存储引擎是否可用以及NO_ENGINE_SUBSTITUTION SQL模式的设置的影响,如“服务器SQL模式”中所述。
      • 为防止数据意外丢失,ALTER TABLE不能将表的存储引擎更改为MERGEBLACKHOLE
    • 要将InnoDB表更改为使用压缩的行存储格式:

      ALTER TABLE t1 ROW_FORMAT = COMPRESSED;
      
    • ENCRYPTION子句启用或禁用表的页面级数据加密InnoDB。必须安装并配置密钥环插件才能启用加密。

      如果table_encryption_privilege_check启用了变量,TABLE_ENCRYPTION_ADMIN则需要特权才能使用其ENCRYPTION设置与默认模式加密设置不同的子句。

      在MySQL 8.0.16之前,该ENCRYPTION子句仅在更改每个表文件表空间中的表时才受支持。从MySQL 8.0.16开始,ENCRYPTION驻留在常规表空间中的表也支持该子句。

      对于驻留在常规表空间中的表,表和表空间的加密必须匹配。

      如果未明确指定ENCRYPTION子句,则不允许通过将表移至其他表空间或更改存储引擎来更改表加密。

      从MySQL 8.0.16开始,如果表使用了不支持加密的存储引擎,则指定的ENCRYPTION子句的值不能是'N'''不允许。以前,该条款已被接受。ENCRYPTION也不允许尝试使用不支持加密的存储引擎在启用了加密的架构中创建不包含子句的表。

      有关更多信息,请参见“ InnoDB静态数据加密”。

    • 重置当前的自动增量值:

      ALTER TABLE t1 AUTO_INCREMENT = 13;
      

      您不能将计数器重置为小于或等于当前使用的值。对于InnoDBMyISAM,如果值小于或等于AUTO_INCREMENT列中当前的最大值,则将该值重置为当前最大AUTO_INCREMENT列值加1。

    • 更改默认表字符集:

      ALTER TABLE t1 CHARACTER SET = utf8;
      

      另请参阅更改字符集。

    • 要添加(或更改)表注释:

      ALTER TABLE t1 COMMENT = 'New table comment';
      
    • ALTER TABLETABLESPACE选项一起使用时,可以InnoDB在现有的常规表空间,每个表文件的表空间和系统表空间之间移动表。请参见使用ALTER TABLE在表空间之间移动表。

      • ALTER TABLE ... TABLESPACE即使该TABLESPACE属性未更改其先前的值,操作也会始终导致整个表的重建。
      • ALTER TABLE ... TABLESPACE语法不支持将表从临时表空间移动到持久表空间。
      • DATA DIRECTORY受所支持的子句CREATE TABLE ... TABLESPACE不受所支持ALTER TABLE ... TABLESPACE,并且如果指定则将被忽略。
      • 有关该TABLESPACE选项的功能和限制的更多信息,请参见CREATE TABLE
    • MySQL NDB Cluster 8.0支持设置NDB_TABLE选项来控制表的分区平衡(碎片计数类型),从任何副本读取功能,完全复制或这些的任意组合,ALTER TABLE以相同的方式作为语句的表注释的一部分如CREATE TABLE本例所示:

      ALTER TABLE t1 COMMENT = "NDB_TABLE=READ_BACKUP=0,PARTITION_BALANCE=FOR_RA_BY_NODE";
      

      请记住,ALTER TABLE ... COMMENT ...该表将丢弃任何现有注释。有关其他信息和示例,请参见设置NDB_TABLE选项。

    要验证是否按预期更改了表选项,请使用SHOW CREATE TABLE或查询INFORMATION_SCHEMA.TABLES表。

    性能和空间要求

    ALTER TABLE使用以下算法之一处理操作:

    • COPY:对原始表的副本执行操作,并将表数据从原始表逐行复制到新表。不允许并发DML。
    • INPLACE:操作避免复制表数据,但可以在适当位置重建表。在操作的准备和执行阶段可以简短地获取表上的独占元数据锁定。通常,支持并发DML。
    • INSTANT:操作只能修改数据字典中的元数据。在准备和执行期间,不会在表上获取任何独占元数据锁,并且表数据不受影响,从而使操作立即进行。允许并发DML。(在MySQL 8.0.12中引入)

    ALGORITHM子句是可选的。如果ALGORITHM省略该子句,则MySQL将使用支持它的ALGORITHM=INSTANT存储引擎和ALTER TABLE子句。否则,ALGORITHM=INPLACE使用。如果ALGORITHM=INPLACE不支持,ALGORITHM=COPY则使用。

    指定ALGORITHM子句要求操作将指定的算法用于支持子句的子句和存储引擎,否则将失败并显示错误。指定ALGORITHM=DEFAULT与省略ALGORITHM子句相同。

    ALTER TABLE使用该COPY算法的操作等待修改表的其他操作完成。将更改应用于表副本后,将数据复制过来,删除原始表,然后将表副本重命名为原始表的名称。ALTER TABLE执行该操作时,其他会话可以读取原始表(不久后会注意到)。在ALTER TABLE操作开始之后开始的表的更新和写入将暂停,直到准备好新表,然后自动将其重定向到新表。该表的临时副本在原始表的数据库目录中创建,除非它是RENAME TO将表移动到位于其他目录中的数据库的操作。

    前面提到的一个例外是,ALTER TABLE在准备好从表和表定义高速缓存中清除过时的表结构时,块读取(而不仅仅是写入)。此时,它必须获得一个排他锁。为此,它等待当前的读取器完成,并阻止新的读取和写入。

    ALTER TABLE使用该COPY算法的操作可防止并发DML操作。仍然允许并发查询。也就是说,表复制操作始终至少包括的并发限制LOCK=SHARED(允许查询但不包括DML)。您可以LOCK通过指定来进一步限制支持该子句的操作的并发性LOCK=EXCLUSIVE,以防止DML和查询。有关更多信息,请参见并发控制。

    要强制将COPY算法用于ALTER TABLE原本不会使用的操作,请指定ALGORITHM=COPY或启用old_alter_table系统变量。如果old_alter_table设置与ALGORITHM值以外DEFAULTALGORITHM子句之间存在冲突,则该子句优先。

    对于InnoDB表,对驻留在共享表空间中的表ALTER TABLE使用COPY算法的操作可能会增加表空间使用的空间量。此类操作需要与表中的数据以及索引一样多的额外空间。对于驻留在共享表空间中的表,操作期间使用的额外空间不会释放回操作系统,就像驻留在每表文件表空间中的表一样。

    有关在线DDL操作的空间要求的信息,请参见“在线DDL空间要求”。

    ALTER TABLE支持该INPLACE算法的操作包括:

    • ALTER TABLEInnoDB在线DDL功能支持的操作。请参见“在线DDL操作”。
    • 重命名表。MySQL重命名与表相对应的文件,tbl_name但不进行复制。(您也可以使用该RENAME TABLE语句来重命名表。请参见“ RENAME TABLE语句”。)专为重命名表授予的特权不会迁移到新名称。必须手动更改它们。
    • 仅修改表元数据的操作。因为服务器不触摸表内容,所以这些操作是立即进行的。仅元数据操作包括:

      • 重命名列。在NDB Cluster 8.0.18和更高版本中,此操作也可以在线执行。
      • 更改列的默认值(NDB表除外)。
      • 只要数据类型的存储大小不变,就可以通过在有效成员值列表的末尾添加新的枚举或设置成员来修改ENUMor或SETcolumn 的定义。例如,将成员添加到具有8个成员的列中,将每个值所需的存储从1字节更改为2字节;这需要一个表副本。在列表中间添加成员会导致对现有成员重新编号,这需要表副本。SET
      • 更改空间列的定义以删除SRID属性。(添加或更改SRID属性确实需要重建,并且无法就地完成,因为服务器必须验证所有值都具有指定的SRID值。)
      • 从MySQL 8.0.14开始,在满足以下条件时更改列字符集:

        • 列数据类型是CHARVARCHAR,一个TEXT类型,或ENUM
        • 字符集更改为从utf8mb3utf8mb4,或任何字符集更改为binary
        • 列上没有索引。
      • 从MySQL 8.0.14开始,在满足以下条件时更改生成的列:

        • 对于InnoDB表,这些语句将修改生成的存储列,但不更改其类型,表达式或可为空性。
        • 对于非InnoDB表,这些语句修改生成的存储列或虚拟列,但不更改其类型,表达式或可为空性。

        此类更改的一个示例是对列注释的更改。

    • 重命名索引。
    • InnoDBNDB表添加或删除辅助索引。请参见“在线DDL操作”。
    • 对于NDB表,是在可变宽度列上添加和删除索引的操作。这些操作在线发生,无需复制表,也不会在大部分时间内阻止并发DML操作。请参见“在NDB群集中使用ALTER TABLE进行在线操作”。
    • 通过ALTER INDEX操作修改索引可见性。
    • DEFAULT如果修改后的列不包含在生成的列表达式中,则包含修改后的列的表的列修改将依赖于带有值的列。例如,NULL可以在不重建表的情况下就地更改单独列的属性。

    ALTER TABLE支持该INSTANT算法的操作包括:

    • 添加一列。此功能称为“即时ADD COLUMN”。有限制条件。请参见“在线DDL操作”。
    • 添加或删除虚拟列。
    • 添加或删除列默认值。
    • 修改ENUMSET列的定义。与上述相同的限制适用于ALGORITHM=INSTANT
    • 更改索引类型。
    • 重命名表。与上述相同的限制适用于ALGORITHM=INSTANT

    有关支持的操作的更多信息ALGORITHM=INSTANT,请参见“在线DDL操作”。

    ALTER TABLE升级的MySQL 5.5的时间列到5.6格式ADD COLUMNCHANGE COLUMNMODIFY COLUMNADD INDEX,和FORCE操作。使用该INPLACE算法无法完成此转换,因为必须重建表,因此ALGORITHM=INPLACE在这些情况下指定会导致错误。ALGORITHM=COPY如有必要,请指定。

    如果ALTER TABLE对用于通过对表进行分区的多列索引的操作KEY更改了列的顺序,则只能使用来执行ALGORITHM=COPY

    WITHOUT VALIDATIONWITH VALIDATION条款影响是否ALTER TABLE执行用于就地操作虚拟生成的列修改。请参见“ ALTER TABLE和Generated Columns”。

    NDB Cluster 8.0支持ALGORITHM=INPLACE使用与标准MySQL Server 相同的语法进行联机操作。有关更多信息,请参见“在NDB群集中使用ALTER TABLE进行在线操作”。

    ALTER TABLE带有DISCARD ... PARTITION ... TABLESPACEIMPORT ... PARTITION ... TABLESPACE不创建任何临时表或临时分区文件。

    ALTER TABLEADD PARTITIONDROP PARTITIONCOALESCE PARTITIONREBUILD PARTITION,或REORGANIZE PARTITION不创建的临时表(当用于除了NDB表);但是,这些操作可以并且确实会创建临时分区文件。

    ADDDROP用于操作RANGELIST分区直接操作或接近。ADDCOALESCE用于操作HASHKEY分区中的所有分区之间复制数据,除非LINEAR HASHLINEAR KEY使用;这实际上与创建新表相同,尽管ADD or COALESCE操作是逐个分区执行的。REORGANIZE操作仅复制已更改的分区,而不会触及未更改的分区。

    对于MyISAM表,可以通过将myisam_sort_buffer_size系统变量设置为较高的值来加快索引的重新创建(更改过程中最慢的部分)。

    并发控制

    对于ALTER TABLE支持它的操作,可以使用该LOCK子句来控制在更改表时对表进行的并发读取和写入的级别。通过为该子句指定非默认值,可以使您在alter操作期间要求一定数量的并发访问或排他性,如果请求的锁定程度不可用,则可以中止操作。

    LOCK = DEFAULT允许使用的操作ALGORITHM=INSTANT。其他LOCK子句参数不适用。

    LOCK子句的参数为:

    • LOCK = DEFAULT
      

      给定ALGORITHM子句(如果有)和ALTER TABLE操作的最大并发级别:如果支持,则允许并发读写。如果不是,则允许并发读取(如果支持)。如果不是,请强制执行独占访问。

    • LOCK = NONE
      

      如果支持,则允许并发读取和写入。否则,将发生错误。

    • LOCK = SHARED
      

      如果支持,则允许并发读取但阻止写入。即使存储引擎为给定的ALGORITHM子句(如果有)和ALTER TABLE操作支持并发写操作,也会阻止写操作。如果不支持并发读取,则会发生错误。

    • LOCK = EXCLUSIVE
      

      强制执行独占访问。即使存储引擎支持给定ALGORITHM子句(如果有)和ALTER TABLE操作并发读取/写入,也可以执行此操作。

    添加和删除列

    使用ADD新列添加到表,DROP删除现有列。是标准SQL的MySQL扩展。DROP col_name

    要在表格行内的特定位置添加列,请使用FIRST或。默认为最后添加该列。AFTER col_name

    如果表仅包含一列,则不能删除该列。如果要删除表,请使用该DROP TABLE语句。

    如果从表中删除了列,则这些列也将从它们所属的任何索引中删除。如果组成索引的所有列均被删除,则索引也将被删除。如果使用CHANGEMODIFY缩短列中存在索引的列,并且结果列长度小于索引长度,则MySQL自动缩短索引。

    对于ALTER TABLE ... ADD,如果该列具有使用不确定函数的表达式默认值,则该语句可能会产生警告或错误。有关详细信息,请参见“使用GTID复制的限制”。

    重命名,重新定义和重新排序列

    CHANGEMODIFYRENAME COLUMN,和ALTER条款允许的名称和现有列的定义被改变。它们具有以下比较特征:

    • CHANGE

      • 可以重命名列并更改其定义,或同时更改两者。
      • 具有比MODIFY或更大的功能RENAME COLUMN,但以某些操作的便利性为代价。CHANGE如果不重命名,则需要两次命名该列;如果仅重命名,则需要重新指定列定义。
      • 使用FIRSTAFTER可以重新排序列。
    • MODIFY

      • 可以更改列定义,但不能更改其名称。
      • CHANGE与更改列定义而不重命名相比更方便。
      • 使用FIRSTAFTER可以重新排序列。
    • RENAME COLUMN

      • 可以更改列名,但不能更改其定义。
      • 比重CHANGE命名列而不更改其定义更方便。
    • ALTER:仅用于更改列默认值。

    CHANGE是标准SQL的MySQL扩展。MODIFY并且RENAME COLUMN是与Oracle兼容的MySQL扩展。

    要更改列以更改其名称和定义,请使用CHANGE,指定旧名称和新名称以及新定义。例如,要将INT NOT NULL列从重命名ab并更改其定义以BIGINT在保留NOT NULL属性的同时使用数据类型,请执行以下操作:

    ALTER TABLE t1 CHANGE a b BIGINT NOT NULL;
    

    要更改列定义但不更改其名称,请使用CHANGEMODIFY。使用时CHANGE,语法需要两个列名称,因此必须两次指定相同的名称,以保持名称不变。例如,要更改column的定义b,请执行以下操作:

    ALTER TABLE t1 CHANGE b b INT NOT NULL;
    

    MODIFY更改定义而不更改名称更方便,因为它只需要一次列名:

    ALTER TABLE t1 MODIFY b INT NOT NULL;
    

    要更改列名但不更改其定义,请使用CHANGERENAME COLUMN。使用CHANGE,语法需要列定义,因此要使定义保持不变,您必须重新指定列当前具有的定义。例如,要将INT NOT NULL列从重命名ba,请执行以下操作:

    ALTER TABLE t1 CHANGE b a INT NOT NULL;
    

    RENAME COLUMN在不更改定义的情况下更方便地更改名称,因为它只需要新旧名称即可:

    ALTER TABLE t1 RENAME COLUMN b TO a;
    

    通常,您不能将列重命名为表中已经存在的名称。但是,有时不是这种情况,例如交换名称或在一个循环中移动它们时。如果表具有名为ab和的列c,则这些是有效的操作:

    -- swap a and b
    ALTER TABLE t1 RENAME COLUMN a TO b,
                   RENAME COLUMN b TO a;
    -- "rotate" a, b, c through a cycle
    ALTER TABLE t1 RENAME COLUMN a TO b,
                   RENAME COLUMN b TO c,
                   RENAME COLUMN c TO a;
    

    对于使用CHANGE或进行的列定义更改MODIFY,定义必须包括数据类型和应应用于新列的所有属性,而不是诸如PRIMARY KEY或的索引属性UNIQUE。原始定义中存在但未为新定义指定的属性不会继续。假设将一列col1定义为,INT UNSIGNED DEFAULT 1 COMMENT 'my column'然后按如下所示修改该列,仅打算将其更改INTBIGINT

    ALTER TABLE t1 MODIFY col1 BIGINT;
    

    这种说法从改变数据类型INTBIGINT,但它也下降了UNSIGNEDDEFAULTCOMMENT属性。要保留它们,该语句必须明确包括它们:

    ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT 'my column';
    

    对于使用CHANGE或进行的数据类型更改MODIFY,MySQL尝试尽可能将现有的列值转换为新的类型。

    警告

    此转换可能会导致数据更改。例如,如果您缩短字符串列,则值可能会被截断。如果在转换为新数据类型会导致数据丢失的情况下阻止操作成功执行,ALTER TABLE请在使用前启用严格的SQL模式(请参见“服务器SQL模式”)。

    如果使用CHANGEMODIFY缩短列中存在索引的列,并且结果列长度小于索引长度,则MySQL自动缩短索引。

    对于用CHANGERENAME COLUMN重命名的列,MySQL自动将这些引用重命名为重命名的列:

    • 引用旧列的索引,包括不可见索引和禁用MyISAM索引。
    • 引用旧列的外键。

    对于用CHANGERENAME COLUMN重命名的列,MySQL不会自动将这些引用重命名为重命名的列:

    • 生成的列和分区表达式引用了重命名的列。您必须使用CHANGE与重新ALTER TABLE命名列的语句相同的语句来重新定义此类表达式。
    • 引用重命名列的视图和存储程序。您必须手动更改这些对象的定义以引用新的列名。

    要内的表,使用重新排序列FIRST,并AFTERCHANGEMODIFY操作。

    ALTER ... SET DEFAULTALTER ... DROP DEFAULT为列指定新的默认值,或分别删除旧的默认值。如果删除了旧的默认值,并且该列可以是NULL,则新的默认值是NULL。如果该列不能为NULL,则MySQL会如“数据类型默认值”中所述分配默认值。

    主键和索引

    DROP PRIMARY KEY删除主键。如果没有主键,则会发生错误。有关主键(尤其是InnoDB表)的性能特征的信息,请参见“主键外键优化”。

    如果sql_require_primary_key启用了系统变量,则尝试删除主键会产生错误。

    如果在表中添加UNIQUE INDEXPRIMARY KEY,MySQL会将其存储在任何非唯一索引之前,以允许尽早检测重复键。

    DROP INDEX删除索引。这是标准SQL的MySQL扩展。请参见“ DROP INDEX语句”。要确定索引名称,请使用。SHOW INDEX FROM tbl_name

    一些存储引擎允许您在创建索引时指定索引类型。index_type说明符的语法为。有关的详细信息,请参见“ CREATE INDEX语句”。首选位置在列列表之后。在将来的MySQL版本中,将删除对列列表之前的选项的使用支持。USING type_nameUSING

    index_option值指定索引的其他选项。USING是这样的选择之一。有关允许index_option值的详细信息,请参见“ CREATE INDEX语句”。

    RENAME INDEX old_index_name TO new_index_name重命名索引。这是标准SQL的MySQL扩展。该表的内容保持不变。old_index_name必须是同一ALTER TABLE语句未删除的表中现有索引的名称。new_index_name是新的索引名称,在应用更改后,该名称不能与结果表中的索引名称重复。索引名称都不能为PRIMARY

    如果您ALTER TABLEMyISAM表上使用,则所有非唯一索引都是在单独的批处理中创建的(与一样REPAIR TABLE)。ALTER TABLE当您有许多索引时,这应该会更快。

    对于MyISAM表,可以显式控制键更新。使用ALTER TABLE ... DISABLE KEYS要告诉MySQL停止更新非唯一索引。然后用于ALTER TABLE ... ENABLE KEYS重新创建丢失的索引。MyISAM用一种比逐个插入密钥快得多的特殊算法来做到这一点,因此在执行批量插入操作之前禁用密钥应该可以大大提高速度。除了前面提到ALTER TABLE ... DISABLE KEYSINDEX特权外,使用还需要特权。

    虽然禁用了非唯一索引,但是对于诸如SELECTEXPLAIN否则会使用它们的语句,它们将被忽略。

    一个后ALTER TABLE声明,可能需要运行ANALYZE TABLE到更新索引集的信息。请参见“ SHOW INDEX语句”。

    ALTER INDEX操作允许使索引可见或不可见。优化器不使用不可见索引。索引可见性的修改适用于除主键(显式或隐式)以外的索引。此功能与存储引擎无关(任何引擎都支持)。有关更多信息,请参见“不可见索引”。

    外键和其他约束

    FOREIGN KEYREFERENCES条款由支持InnoDBNDB存储引擎,它实现。请参见“外键约束”。对于其他存储引擎,这些子句会被解析但会被忽略。ADD[CONSTRAINT[symbol]] FOREIGN KEY[index_name](...)REFERENCES ...(...)

    对于ALTER TABLE,与不同CREATE TABLEADD FOREIGN KEY忽略index_name如果给出,则使用自动生成的外键名称。解决方法是,包括该CONSTRAINT子句以指定外键名称:

    ADD CONSTRAINT name FOREIGN KEY (....) ...
    
    重要

    MySQL默默地忽略了内联REFERENCES规范,其中引用被定义为列规范的一部分。MySQL仅接受REFERENCES定义为单独FOREIGN KEY规范一部分的子句。

    注意

    分区InnoDB表不支持外键。此限制不适用于NDB表,包括由明确分区的表[LINEAR] KEY。有关更多信息,请参见“与存储引擎有关的分区限制”。

    MySQL Server和NDB Cluster都支持使用ALTER TABLE删除外键:

    ALTER TABLE tbl_name DROP FOREIGN KEY fk_symbol;
    

    ALTER TABLE支持ALTER TABLE ... ALGORITHM=INPLACE但不支持在同一语句中添加和删除外键ALTER TABLE ... ALGORITHM=COPY

    服务器禁止更改外键列,这可能会导致丢失引用完整性。解决方法是ALTER TABLE ... DROP FOREIGN KEY在更改列定义之前和ALTER TABLE ... ADD FOREIGN KEY之后使用。禁止更改的示例包括:

    • 更改外键列的数据类型可能是不安全的。例如,允许更改VARCHAR(20)VARCHAR(30),但不允许更改为,VARCHAR(1024)因为这会更改存储单个值所需的长度字节数。
    • 禁止将NULL列更改NOT NULL为非严格模式,以防止将NULL值转换为默认非NULL值,在参考表中没有默认值。在严格模式下允许该操作,但是如果需要任何此类转换,则会返回错误。

    ALTER TABLE tbl_name RENAME new_tbl_name改变了以字符串内部生成的外键约束名称和用户定义的外键约束的名字“tbl_name_ibfk_ ”,以反映新表名。InnoDB将以字符串“tbl_name_ibfk_ ”开头的外键约束名称解释为内部生成的名称。

    在MySQL 8.0.16之前,ALTER TABLE仅允许以下有限版本的CHECK约束添加语法被解析和忽略:

    ADD CHECK (expr)
    

    从MySQL 8.0.16开始,ALTER TABLE允许CHECK添加,删除或更改现有表的约束:

    • 添加一个新的CHECK约束:

      ALTER TABLE tbl_name
          ADD CONSTRAINT [symbol] CHECK (expr) [[NOT] ENFORCED];
      

      约束语法元素的含义与相同CREATE TABLE。请参见“检查约束”。

    • 删除一个CHECK名为的现有约束symbol

      ALTER TABLE tbl_name
          DROP CHECK symbol;
      
    • 更改是否强制执行CHECK名为的现有约束symbol

      ALTER TABLE tbl_name
          ALTER CHECK symbol [NOT] ENFORCED;
      

    DROP CHECKALTER CHECK条款是MySQL的扩展标准SQL。

    从MySQL 8.0.19开始,ALTER TABLE允许使用更通用(和SQL标准)的语法来删除和更改任何类型的现有约束,其中约束类型由约束名称确定:

    • 删除一个名为的现有约束symbol

      ALTER TABLE tbl_name
          DROP CONSTRAINT symbol;
      

      如果sql_require_primary_key启用了系统变量,则尝试删除主键会产生错误。

    • 更改是否symbol强制执行名为的现有约束:

      ALTER TABLE tbl_name
          ALTER CONSTRAINT symbol [NOT] ENFORCED;
      

      只有CHECK约束可以更改为不强制执行。所有其他约束类型始终被强制执行。

    SQL标准指定所有类型的约束(主键,唯一索引,外键,检查)都属于同一名称空间。在MySQL中,每个约束类型在每个模式都有自己的名称空间。因此,每种约束类型的名称在每个架构中必须唯一,但是不同类型的约束可以具有相同的名称。当多个约束具有相同的名称,DROP CONSTRAINT并且ADD CONSTRAINT是不明确的,就会发生错误。在这种情况下,必须使用特定于约束的语法来修改约束。例如,使用DROP PRIMARY KEY或DROP FOREIGN KEY删除主键或外键。

    如果表更改导致违反强制CHECK约束,则会发生错误并且表不会被修改。发生错误的操作示例:

    • 尝试将AUTO_INCREMENT属性添加到CHECK约束中使用的列中。
    • 尝试添加强制CHECK约束或强制CHECK现有行违反约束条件的非强制约束。
    • 尝试修改,重命名或删除CHECK约束中使用的列,除非该约束也被删除在同一条语句中。例外:如果CHECK约束仅引用单个列,则删除该列会自动删除该约束。

    ALTER TABLE tbl_name RENAME new_tbl_name更改内部生成的和用户定义的CHECK约束名称,这些约束名称以字符串“tbl_name_chk_ ”开头以反映新的表名称。MySQL CHECK将以字符串“tbl_name_chk_ ”开头的约束名称解释为内部生成的名称。

    更改字符集

    要更改默认的表字符集和所有字符列(CHARVARCHARTEXT)到一个新的字符集,可使用如下语句:

    ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
    

    该语句还更改所有字符列的排序规则。如果您没有指定任何COLLATE子句来指示要使用哪种排序规则,则该语句将默认排序规则用于字符集。如果此排序规则不适合预期的表使用(例如,如果它将从区分大小写的排序规则更改为不区分大小写的排序规则),则显式指定排序规则。

    对于具有的数据类型的列VARCHAR或一个TEXT类型,CONVERT TO CHARACTER SET改变数据类型必须确保新列是足够长的时间来存储尽可能多的字符原始列。例如,一TEXT列有两个长度的字节,它们存储列中值的字节长度,最大为65,535。对于一latin1TEXT列,每个字符都需要一个字节,因此该列最多可以存储65,535个字符。如果将列转换为utf8,则每个字符最多可能需要三个字节,最大可能的长度为3×65,535 = 196,605字节。该长度不适合TEXT列的长度字节,因此MySQL将数据类型转换为MEDIUMTEXT,这是长度字节可以记录196,605的最小字符串类型。同样,VARCHAR列可能会转换为MEDIUMTEXT

    为避免数据类型更改为刚刚描述的类型,请勿使用CONVERT TO CHARACTER SET。而是使用MODIFY更改单个列。例如:

    ALTER TABLE t MODIFY latin1_text_col TEXT CHARACTER SET utf8;
    ALTER TABLE t MODIFY latin1_varchar_col VARCHAR(M) CHARACTER SET utf8;
    

    如果您指定CONVERT TO CHARACTER SET binaryCHARVARCHARTEXT列转换为它们相应的二进制字符串类型(BINARYVARBINARYBLOB)。这意味着这些列将不再具有字符集,并且后续CONVERT TO操作将不适用于它们。

    如果charset_nameDEFAULT在一个CONVERT TO CHARACTER SET操作中,由命名的字符集character_set_database被用于系统变量。

    警告

    CONVERT TO操作在原始字符集和命名字符集之间转换列值。如果您在一个字符集(例如)中有一列,那么这不是您想要的,latin1但是存储的值实际上使用其他不兼容的字符集(例如utf8)。在这种情况下,您必须为每个此类列执行以下操作:

    ALTER TABLE t1 CHANGE c1 c1 BLOB;
    ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
    

    之所以可行,是因为您在与BLOB列之间进行转换时不进行转换。

    要仅更改表的默认字符集,请使用以下语句:

    ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;
    

    这个词DEFAULT是可选的。默认字符集是如果不为稍后添加到表中的列指定字符集时使用的字符集(例如,使用ALTER TABLE ... ADD column)。

    foreign_key_checks启用了系统变量,这是默认设置,字符集转换不包括外键约束中使用的字符串列的表允许的。解决方法是foreign_key_checks在执行字符集转换之前禁用。重新启用之前,必须对涉及外键约束的两个表都执行转换foreign_key_checks。如果foreign_key_checks仅在转换一个表之后重新启用,则由于这些操作期间发生隐式转换,所以ON DELETE CASCADEor ON UPDATE CASCADE操作可能会破坏引用表中的数据(错误#45290,错误#74816)。

    导入InnoDB表

    一个InnoDB在自己创建的表文件的每个表的表空间可以从备份或使用另一个MySQL服务器实例导入DISCARD TABLEPACEIMPORT TABLESPACE条款。请参见“导入InnoDB表”。

    MyISAM表的行顺序

    ORDER BY使您可以按特定顺序创建包含行的新表。该选项主要在您知道大多数情况下以某种顺序查询行时才有用。通过在对该表进行重大更改之后使用此选项,可能会获得更高的性能。在某些情况下,如果表按要稍后排序的列排序,则对于MySQL排序可能会更容易。

    注意

    插入和删除后,表未按指定顺序保留。

    ORDER BY语法允许指定一个或多个列名进行排序,每个列名都可以分别跟随ASCDESC指示升序或降序。默认为升序。只允许使用列名作为排序条件;不允许使用任意表达式。该条款应在其他任何条款之后最后给出。

    ORDER BYInnoDB表没有意义,因为InnoDB总是根据聚簇索引对表行进行排序。

    在分区表上使用时,ALTER TABLE ... ORDER BY仅对每个分区内的行进行排序。

    分区选项

    partition_options表示可与分区表一起使用的选项,用于重新分区,添加,删除,丢弃,导入,合并和拆分分区以及执行分区维护。

    这是可能的ALTER TABLE语句包含一个PARTITION BYREMOVE PARTITIONING子句中,除其他更改规格,但PARTITION BY还是REMOVE PARTITIONING子句必须最后任何其他规格后指定。的ADD PARTITIONDROP PARTITIONDISCARD PARTITIONIMPORT PARTITIONCOALESCE PARTITIONREORGANIZE PARTITIONEXCHANGE PARTITIONANALYZE PARTITIONCHECK PARTITION,和REPAIR PARTITION选项不能与其他单一更改规格组合ALTER TABLE,因为选择刚上市就单个分区的行为。

    有关分区选项的更多信息,请参见“ CREATE TABLE语句”和“ ALTER TABLE分区操作”。有关ALTER TABLE ... EXCHANGE PARTITION语句的信息和示例,请参见“用表交换分区和子分区”。