文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  CREATE TABLE ... SELECT 语句

15.1.20.4 CREATE TABLE ... SELECT 语句

您可以通过在 CREATE TABLE 语句的末尾添加 SELECT 语句,从一个表创建另一个表。

CREATE TABLE new_tbl [AS] SELECT * FROM orig_tbl;

MySQL 会为 SELECT 中的所有元素创建新列。例如:

mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
    ->        PRIMARY KEY (a), KEY(b))
    ->        ENGINE=InnoDB SELECT b,c FROM test2;

这将创建一个包含三列(abc)的 InnoDB 表。ENGINE 选项是 CREATE TABLE 语句的一部分,不应在 SELECT 之后使用;这将导致语法错误。其他 CREATE TABLE 选项(如 CHARSET)也是如此。

请注意,SELECT 语句中的列会附加到表的右侧,而不是与其重叠。以下面的示例为例:

mysql> SELECT * FROM foo;
+---+
| n |
+---+
| 1 |
+---+

mysql> CREATE TABLE bar (m INT) SELECT n FROM foo;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM bar;
+------+---+
| m    | n |
+------+---+
| NULL | 1 |
+------+---+
1 row in set (0.00 sec)

对于表 foo 中的每一行,都会在 bar 中插入一行,其中包含来自 foo 的值以及新列的默认值。

CREATE TABLE ... SELECT 生成的表中,仅在 CREATE TABLE 部分命名的列排在前面。在两个部分中都命名或仅在 SELECT 部分命名的列排在后面。SELECT 列的数据类型可以通过在 CREATE TABLE 部分中指定该列来覆盖。

对于同时支持原子 DDL 和外键约束的存储引擎,在使用基于行的复制时,CREATE TABLE ... SELECT 语句中不允许创建外键。可以使用 ALTER TABLE 在以后添加外键约束。

您可以在 SELECT 之前加上 IGNOREREPLACE,以指示如何处理与唯一键值重复的行。使用 IGNORE 时,将丢弃与唯一键值上的现有行重复的行。使用 REPLACE 时,新行将替换具有相同唯一键值的行。如果既未指定 IGNORE 也未指定 REPLACE,则重复的唯一键值将导致错误。有关更多信息,请参阅IGNORE 对语句执行的影响

您还可以在 CREATE TABLE ... SELECTSELECT 部分中使用 VALUES 语句;该语句的 VALUES 部分必须包含使用 AS 子句的表别名。要命名来自 VALUES 的列,请为表别名提供列别名;否则,将使用默认列名 column_0column_1column_2 等。

否则,由此创建的表中的列命名遵循本节前面描述的相同规则。示例

mysql> CREATE TABLE tv1
     >     SELECT * FROM (VALUES ROW(1,3,5), ROW(2,4,6)) AS v;
mysql> TABLE tv1;
+----------+----------+----------+
| column_0 | column_1 | column_2 |
+----------+----------+----------+
|        1 |        3 |        5 |
|        2 |        4 |        6 |
+----------+----------+----------+

mysql> CREATE TABLE tv2
     >     SELECT * FROM (VALUES ROW(1,3,5), ROW(2,4,6)) AS v(x,y,z);
mysql> TABLE tv2;
+---+---+---+
| x | y | z |
+---+---+---+
| 1 | 3 | 5 |
| 2 | 4 | 6 |
+---+---+---+

mysql> CREATE TABLE tv3 (a INT, b INT, c INT)
     >     SELECT * FROM (VALUES ROW(1,3,5), ROW(2,4,6)) AS v(x,y,z);
mysql> TABLE tv3;
+------+------+------+----------+----------+----------+
| a    | b    | c    |        x |        y |        z |
+------+------+------+----------+----------+----------+
| NULL | NULL | NULL |        1 |        3 |        5 |
| NULL | NULL | NULL |        2 |        4 |        6 |
+------+------+------+----------+----------+----------+

mysql> CREATE TABLE tv4 (a INT, b INT, c INT)
     >     SELECT * FROM (VALUES ROW(1,3,5), ROW(2,4,6)) AS v(x,y,z);
mysql> TABLE tv4;
+------+------+------+---+---+---+
| a    | b    | c    | x | y | z |
+------+------+------+---+---+---+
| NULL | NULL | NULL | 1 | 3 | 5 |
| NULL | NULL | NULL | 2 | 4 | 6 |
+------+------+------+---+---+---+

mysql> CREATE TABLE tv5 (a INT, b INT, c INT)
     >     SELECT * FROM (VALUES ROW(1,3,5), ROW(2,4,6)) AS v(a,b,c);
mysql> TABLE tv5;
+------+------+------+
| a    | b    | c    |
+------+------+------+
|    1 |    3 |    5 |
|    2 |    4 |    6 |
+------+------+------+

当选择所有列并使用默认列名时,可以省略 SELECT *,因此用于创建表 tv1 的语句也可以写成如下所示

mysql> CREATE TABLE tv1 VALUES ROW(1,3,5), ROW(2,4,6);
mysql> TABLE tv1;
+----------+----------+----------+
| column_0 | column_1 | column_2 |
+----------+----------+----------+
|        1 |        3 |        5 |
|        2 |        4 |        6 |
+----------+----------+----------+

当使用 VALUES 作为 SELECT 的来源时,始终会将所有列都选择到新表中,并且不能像从命名表中选择那样选择单个列;以下每个语句都会产生错误(ER_OPERAND_COLUMNS

CREATE TABLE tvx
    SELECT (x,z) FROM (VALUES ROW(1,3,5), ROW(2,4,6)) AS v(x,y,z);

CREATE TABLE tvx (a INT, c INT)
    SELECT (x,z) FROM (VALUES ROW(1,3,5), ROW(2,4,6)) AS v(x,y,z);

同样,您可以在 SELECT 的位置使用 TABLE 语句。这遵循与 VALUES 相同的规则;源表的所有列及其在源表中的名称始终插入到新表中。示例

mysql> TABLE t1;
+----+----+
| a  | b  |
+----+----+
|  1 |  2 |
|  6 |  7 |
| 10 | -4 |
| 14 |  6 |
+----+----+

mysql> CREATE TABLE tt1 TABLE t1;
mysql> TABLE tt1;
+----+----+
| a  | b  |
+----+----+
|  1 |  2 |
|  6 |  7 |
| 10 | -4 |
| 14 |  6 |
+----+----+

mysql> CREATE TABLE tt2 (x INT) TABLE t1;
mysql> TABLE tt2;
+------+----+----+
| x    | a  | b  |
+------+----+----+
| NULL |  1 |  2 |
| NULL |  6 |  7 |
| NULL | 10 | -4 |
| NULL | 14 |  6 |
+------+----+----+

由于无法始终确定底层 SELECT 语句中行的顺序,因此 CREATE TABLE ... IGNORE SELECTCREATE TABLE ... REPLACE SELECT 语句被标记为对于基于语句的复制不安全。此类语句在使用基于语句的模式时会在错误日志中生成警告,并在使用 MIXED 模式时使用基于行的格式写入二进制日志。另请参阅第 19.2.1.1 节“基于语句的复制和基于行的复制的优缺点”

CREATE TABLE ... SELECT 不会自动为您创建任何索引。这样做是有意使该语句尽可能灵活。如果您希望在创建的表中包含索引,则应在 SELECT 语句之前指定这些索引

mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;

对于 CREATE TABLE ... SELECT,目标表不会保留有关所选表中的列是否是生成列的信息。语句的 SELECT 部分不能为目标表中的生成列赋值。

对于 CREATE TABLE ... SELECT,目标表会保留原始表中的表达式默认值。

可能会发生一些数据类型的转换。例如,AUTO_INCREMENT 属性不会保留,并且 VARCHAR 列可能会变为 CHAR 列。重新训练的属性是 NULL(或 NOT NULL)以及那些具有它们的列的 CHARACTER SETCOLLATIONCOMMENTDEFAULT 子句。

使用 CREATE TABLE ... SELECT 创建表时,请确保为查询中的任何函数调用或表达式添加别名。如果不这样做,CREATE 语句可能会失败或导致列名不符合预期。

CREATE TABLE artists_and_works
  SELECT artist.name, COUNT(work.artist_id) AS number_of_works
  FROM artist LEFT JOIN work ON artist.id = work.artist_id
  GROUP BY artist.id;

您还可以为创建的表中的列显式指定数据类型

CREATE TABLE foo (a TINYINT NOT NULL) SELECT b+1 AS a FROM bar;

对于 CREATE TABLE ... SELECT,如果给出了 IF NOT EXISTS 并且目标表存在,则不会向目标表中插入任何内容,并且不会记录该语句。

为了确保可以使用二进制日志重新创建原始表,MySQL 不允许在 CREATE TABLE ... SELECT 期间并发插入。有关更多信息,请参阅第 15.1.1 节“原子数据定义语句支持”

您不能在 CREATE TABLE new_table SELECT ... FROM old_table ... 等语句中将 FOR UPDATE 用作 SELECT 的一部分。如果您尝试这样做,该语句将失败。

CREATE TABLE ... SELECT 操作仅将 ENGINE_ATTRIBUTESECONDARY_ENGINE_ATTRIBUTE 值应用于列。表和索引 ENGINE_ATTRIBUTESECONDARY_ENGINE_ATTRIBUTE 值不会应用于新表,除非显式指定。