您可以通过在 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;
这将创建一个具有三个列 a
、b
和 c
的 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
前添加 IGNORE
或 REPLACE
,以指示如何处理唯一键值的重复行。使用 IGNORE
,重复的行将被丢弃。使用 REPLACE
,新行将替换具有相同唯一键值的行。如果既不指定 IGNORE
也不指定 REPLACE
,则唯一键值的重复将导致错误。有关更多信息,请参阅 IGNORE 对语句执行的影响。
您还可以在 SELECT
部分使用 VALUES
语句;VALUES
部分的语句必须使用 AS
子句指定表别名。要命名来自 VALUES
的列,需要在表别名中提供列别名;否则,将使用默认列名 column_0
、column_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 | 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 SELECT
和CREATE 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 SET
、COLLATION
、COMMENT
和DEFAULT
子句。
创建表时使用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_ATTRIBUTE
和 SECONDARY_ENGINE_ATTRIBUTE
值应用于列。表和索引的 ENGINE_ATTRIBUTE
和 SECONDARY_ENGINE_ATTRIBUTE
值不会应用于新表,除非明确指定。