Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  CREATE TABLE ... SELECT Statement

15.1.20.4 创建表 ... 选择语句

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

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;

这将创建一个具有三个列 abcInnoDB 表。 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 对语句执行的影响

您还可以在 SELECT 部分使用 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);

类似地,您可以使用 TABLE 语句代替 SELECT。这遵循与 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 语句中使用 FOR UPDATE,例如:SELECT 语句中,例如:CREATE TABLE new_table SELECT ... FROM old_table ...。如果您尝试这样做,语句将失败。

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