Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 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;

这创建了一个InnoDB表,具有三个列:abcENGINE选项是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部分命名的列排在前面。同时出现在CREATE TABLESELECT部分命名的列排在后面。同时出现在SELECT部分命名的列的数据类型可以被CREATE TABLE部分override。

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

您可以在SELECT前面添加IGNOREREPLACE,以指示如何处理唯一键值重复的行。使用IGNORE,重复唯一键值的行将被忽略;使用REPLACE,新行将替换具有相同唯一键值的行。如果既不指定IGNORE也不指定REPLACE,重复唯一键值将导致错误。更多信息,请参见忽略语句执行的影响

您还可以在VALUES语句中使用SELECT部分的CREATE TABLE ... SELECTVALUES语句的一部分必须包含一个使用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 语句被标记为不安全的语句,对于语句基于的复制模式下在错误日志中产生警告,并且在使用混合模式时使用行基于的格式写入二进制日志。请参见第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节,“原子数据定义语句支持”

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

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