#### 13.1.20.4 CREATE TABLE ... SELECT 语句

[](<>)[](<>)

您可以通过添加一个从另一个表创建一个表[`选择`](select.html)在结尾处声明[`创建表`](create-table.html)陈述：

```
CREATE TABLE new_tbl [AS] SELECT * FROM orig_tbl;
```

MySQL 为所有元素创建新列[`选择`](select.html).例如：

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

这创建了一个[`InnoDB`](innodb-storage-engine.html)三列表格，`一种`,`b`， 和`c`.这`引擎`选项是[`创建表`](create-table.html)声明，并且不应该在下面使用[`选择`](select.html);这将导致语法错误。其他的也一样[`创建表`](create-table.html)选项，例如`字符集`.

请注意，从[`选择`](select.html)语句附加到表格的右侧，而不是重叠在上面。举个例子：

```
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)
```

对于表中的每一行`富`，插入一行`酒吧`值来自`富`和新列的默认值。

在一个表格中[`创建表...选择`](create-table.html), 列仅在[`创建表`](create-table.html)部分先来。列在两个部分中或仅在[`选择`](select.html)部分是在那之后。的数据类型[`选择`](select.html)列也可以通过在[`创建表`](create-table.html)部分。

如果在将数据复制到表时发生错误，则表会自动删除而不是创建。然而，在 MySQL 8.0.21 之前，当使用基于行的复制时，一个[`创建表...选择`](create-table-select.html)语句在二进制日志中记录为两个事务，一个用于创建表，另一个用于插入数据。当从二进制日志应用语句时，两个事务之间的故障或复制数据时可能导致复制空表。MySQL 8.0.21 中删除了该限制。在支持 atomic DDL 的存储引擎上，[`创建表...选择`](create-table-select.html)现在，当使用基于行的复制时，它被记录并作为一个事务应用。有关详细信息，请参阅[第 13.1.1 节，“原子数据定义语句支持”](atomic-ddl.html).

从 MySQL 8.0.21 开始，在同时支持原子 DDL 和外键约束的存储引擎上，不允许创建外键[`创建表...选择`](create-table-select.html)使用基于行的复制时的语句。以后可以使用外键约束添加[`更改表`](alter-table.html).

你可以先于[`选择`](select.html)经过`忽视`要么`代替`指示如何处理重复唯一键值的行。和`忽视`，与唯一键值上的现有行重复的行将被丢弃。和`代替`, 新行替换具有相同唯一键值的行。如果两者都没有`忽视`也不`代替`指定时，重复的唯一键值会导致错误。有关详细信息，请参阅[IGNORE 对语句执行的影响](sql-mode.html#ignore-effect-on-execution).

在 MySQL 8.0.19 及更高版本中，您还可以使用[`价值观`](values.html)中的声明[`选择`](select.html)部分`创建表...选择`;这`价值观`语句的一部分必须包含一个表别名，使用`作为`条款。命名来自的列`价值观`，为表别名提供列别名；否则，默认列名`列_0`,`列_1`,`column_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    | column_0 | column_1 | column_2 |
+------+------+------+----------+----------+----------+
| 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 |
+------+------+------+
```

选择所有列并使用默认列名时，可以省略`选择 *`，所以该语句只是用于创建表`电视1`也可以这样写：

```
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.html)作为源[`选择`](select.html)，所有列总是被选择到新表中，并且不能像从命名表中选择时那样选择单个列；以下每个语句都会产生错误（[`ER_OPERAND_COLUMNS`](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_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);
```

同样，您可以使用[`桌子`](table.html)代替的声明[`选择`](select.html).这遵循与[`价值观`](values.html);源表的所有列及其在源表中的名称始终插入到新表中。例子：

```
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.html)陈述不能总是被确定，`创建表...忽略选择`和`创建表...替换选择`对于基于语句的复制，语句被标记为不安全。此类语句在使用 statement-based 模式时会在错误日志中产生警告，并在使用时使用 row-based 格式写入二进制日志`混合`模式。也可以看看[第 17.2.1.1 节，“基于语句和基于行的复制的优缺点”](replication-sbr-rbr.html).

[`创建表...选择`](create-table.html)不会自动为您创建任何索引。这样做是为了使语句尽可能灵活。如果你想在创建的表中有索引，你应该在[`选择`](select.html)陈述：

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

为了`创建表...选择`，目标表不保留有关选定表中的列是否为生成列的信息。这[`选择`](select.html)语句的一部分不能将值分配给目标表中生成的列。

为了`创建表...选择`，目标表会保留原始表中的表达式默认值。

可能会发生一些数据类型的转换。例如，`自动递增`不保留属性，并且[`VARCHAR`](char.html)列可以变成[`字符`](char.html)列。重新训练的属性是`空值`（要么`非空`) 并且，对于那些拥有它们的列，`字符集`,`整理`,`评论`, 和`默认`条款。

当创建一个表时[`创建表...选择`](create-table-select.html)，请确保为查询中的任何函数调用或表达式设置别名。如果您不这样做，则`创建`语句可能会失败或导致不需要的列名。

```
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.html)， 如果`如果不存在`给出并且目标表存在，没有任何内容插入到目标表中，并且不记录该语句。

为了保证二进制日志可以用来重新创建原始表，MySQL 不允许在执行过程中进行并发插入。[`创建表...选择`](create-table.html).然而，在 MySQL 8.0.21 之前，当一个[`创建表...选择`](create-table.html)当使用基于行的复制时，从二进制日志应用操作，复制数据时允许在复制表上进行并发插入。MySQL 8.0.21 在支持 atomic DDL 的存储引擎上删除了该限制。有关详细信息，请参阅[第 13.1.1 节，“原子数据定义语句支持”](atomic-ddl.html).

你不能使用`更新`作为一部分[`选择`](select.html)在诸如[`创建表 *`新表`* 选择 ... 从 *`旧表`* ...`](create-table-select.html).如果您尝试这样做，则该语句将失败。

[`创建表...选择`](create-table-select.html)操作适用`引擎属性`和`SECONDARY_ENGINE_ATTRIBUTE`仅对列的值。表格和索引`引擎属性`和`SECONDARY_ENGINE_ATTRIBUTE`除非明确指定，否则值不会应用于新表。
