文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  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;

这将创建一个具有三个列 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 部分命名的列排在后面。可以通过在 CREATE TABLE 部分中也指定列来覆盖 SELECT 列的数据类型。

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

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

还可以在 SELECT 部分的 CREATE TABLE ... 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 节,“原子数据定义语句支持”

无法使用 FOR UPDATE 作为 SELECT 的一部分,用于诸如 CREATE TABLE new_table SELECT ... FROM old_table ... 之类的语句。如果尝试这样做,语句将失败。

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