您可以使用在 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;
這會建立一個具有三個資料行 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 對於語句執行的影響。
您也可以在 CREATE TABLE ... SELECT
的 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 節「原子資料定義語句支援」。
您不能將 FOR UPDATE
作為 SELECT
的一部分用於類似 CREATE TABLE
之類的語句中。如果您嘗試這樣做,語句將會失敗。new_table
SELECT ... FROM old_table
...
CREATE TABLE ... SELECT
作業僅將 ENGINE_ATTRIBUTE
和 SECONDARY_ENGINE_ATTRIBUTE
值套用至資料行。除非明確指定,否則資料表和索引 ENGINE_ATTRIBUTE
和 SECONDARY_ENGINE_ATTRIBUTE
值不會套用至新的資料表。