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
包含三列的表,a
、b
和
c
。该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)
对于 tablefoo
中的每一行,都会插入一行,其中包含新列bar
的值
foo
和默认值。
在由 生成的表中
CREATE TABLE ...
SELECT
,仅在
CREATE TABLE
部分中命名的列排在第一位。在这两个部分中命名的列或仅在该
SELECT
部分中命名的列在其后。SELECT
还可以通过在部件中指定列来覆盖列
的数据类型CREATE TABLE
。
如果在将数据复制到表时发生错误,则表会自动删除而不创建。但是在MySQL 8.0.21之前,使用行复制时,一条
CREATE
TABLE ... SELECT
语句在二进制日志中记录为两个事务,一个创建表,一个插入数据。当从二进制日志应用语句时,两个事务之间的失败或复制数据时可能导致复制空表。MySQL 8.0.21 中删除了该限制。在支持原子 DDL 的存储引擎上,CREATE
TABLE ... SELECT
当使用基于行的复制时,现在记录并应用为一个事务。有关详细信息,请参阅第 13.1.1 节,“原子数据定义语句支持”.
从 MySQL 8.0.21 开始,在支持原子 DDL 和外键约束的存储引擎上,当使用基于行的复制时,不允许在
CREATE
TABLE ... SELECT
语句中创建外键。稍后可以使用添加外键约束
ALTER TABLE
。
您可以在SELECT
by
IGNORE
或之前REPLACE
指示如何处理重复唯一键值的行。使用IGNORE
,与唯一键值上的现有行重复的行将被丢弃。使用
REPLACE
,新行替换具有相同唯一键值的行。如果既未指定IGNORE
也未
REPLACE
指定,则重复的唯一键值会导致错误。有关详细信息,请参阅
IGNORE 对语句执行的影响。
在 MySQL 8.0.19 及之后的版本中,还可以
在;部分使用VALUES
语句
。该
语句的部分必须包含一个使用
子句的表别名。要命名来自 的列
,请使用表别名提供列别名;否则,将使用默认列名
, ,
, ...。
SELECT
CREATE
TABLE ... SELECT
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 | 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 |
+------+------+------+
选择所有列,使用默认列名时,可以省略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
。另见
第 17.2.1.1 节,“基于语句和基于行的复制的优点和缺点”。
CREATE TABLE ...
SELECT
不会自动为您创建任何索引。这样做是为了使语句尽可能灵活。如果你想在创建的表中有索引,你应该在
SELECT
语句之前指定这些:
mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;
对于CREATE TABLE ... SELECT
,目标表不保留有关 selected-from 表中的列是否为生成列的信息。该
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
. 但是,在 MySQL 8.0.21 之前,当
CREATE TABLE ...
SELECT
使用基于行的复制时从二进制日志应用操作时,在复制数据时允许在复制表上进行并发插入。在支持原子 DDL 的存储引擎上,MySQL 8.0.21 中删除了该限制。有关详细信息,请参阅
第 13.1.1 节,“原子数据定义语句支持”。
您不能将FOR UPDATE
用作语句的一部分,
SELECT
例如
. 如果您尝试这样做,该语句将失败。
CREATE
TABLE
new_table
SELECT ... FROM
old_table
...
CREATE
TABLE ... SELECT
操作仅适用
ENGINE_ATTRIBUTE
于
SECONDARY_ENGINE_ATTRIBUTE
列。除非明确指定,否则表和索引ENGINE_ATTRIBUTE
以及
SECONDARY_ENGINE_ATTRIBUTE
值不会应用于新表。