本節討論衍生表格的一般特性。關於以 LATERAL
關鍵字開頭的橫向衍生表格的資訊,請參閱第 15.2.15.9 節「橫向衍生表格」。
衍生表格是在查詢的 FROM
子句範圍內產生表格的運算式。例如,SELECT
陳述式的 FROM
子句中的子查詢就是衍生表格。
SELECT ... FROM (subquery) [AS] tbl_name ...
JSON_TABLE()
函數會產生表格,並提供另一種建立衍生表格的方式。
SELECT * FROM JSON_TABLE(arg_list) [AS] tbl_name ...
[AS]
子句是強制性的,因為 tbl_name
FROM
子句中的每個表格都必須有名稱。衍生表格中的任何欄位都必須有唯一的名稱。或者,tbl_name
後面可以接一個用括號括住的衍生表格欄位名稱清單。
SELECT ... FROM (subquery) [AS] tbl_name (col_list) ...
欄位名稱的數量必須與表格欄位的數量相同。
為了方便說明,假設您有這個表格
CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
以下是如何在 FROM
子句中使用子查詢,使用範例表格
INSERT INTO t1 VALUES (1,'1',1.0);
INSERT INTO t1 VALUES (2,'2',2.0);
SELECT sb1,sb2,sb3
FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb
WHERE sb1 > 1;
結果
+------+------+------+
| sb1 | sb2 | sb3 |
+------+------+------+
| 2 | 2 | 4 |
+------+------+------+
這是另一個範例:假設您想知道分組表格的一組總和的平均值。這無法運作
SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
但是,這個查詢會提供所需的資訊
SELECT AVG(sum_column1)
FROM (SELECT SUM(column1) AS sum_column1
FROM t1 GROUP BY column1) AS t1;
請注意,子查詢中使用的欄位名稱 (sum_column1
) 在外部查詢中可被識別。
衍生表格的欄位名稱來自其選擇清單。
mysql> SELECT * FROM (SELECT 1, 2, 3, 4) AS dt;
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
若要明確提供欄位名稱,請在衍生表格名稱後面加上括號括住的欄位名稱清單。
mysql> SELECT * FROM (SELECT 1, 2, 3, 4) AS dt (a, b, c, d);
+---+---+---+---+
| a | b | c | d |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
+---+---+---+---+
衍生表格可以傳回純量、欄位、列或表格。
衍生表格受限於這些限制:
衍生表格不能包含對同一個
SELECT
的其他表格的參考 (請使用LATERAL
衍生表格;請參閱第 15.2.15.9 節「橫向衍生表格」)。
最佳化工具會以這樣的方式決定衍生表格的資訊,使得 EXPLAIN
不需要將其具體化。請參閱第 10.2.2.4 節「使用合併或具體化來最佳化衍生表格、檢視參考和通用表格運算式」。
在某些情況下,使用 EXPLAIN SELECT
可能會修改表格資料。如果外部查詢存取任何表格,且內部查詢調用會變更表格中一或多列的預存函數,就可能發生這種情況。假設資料庫 d1
中有兩個表格 t1
和 t2
,以及一個會修改 t2
的預存函數 f1
,建立如下所示:
CREATE DATABASE d1;
USE d1;
CREATE TABLE t1 (c1 INT);
CREATE TABLE t2 (c1 INT);
CREATE FUNCTION f1(p1 INT) RETURNS INT
BEGIN
INSERT INTO t2 VALUES (p1);
RETURN p1;
END;
直接在 EXPLAIN SELECT
中參考該函數對 t2
沒有影響,如下所示:
mysql> SELECT * FROM t2;
Empty set (0.02 sec)
mysql> EXPLAIN SELECT f1(5)\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
partitions: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: No tables used
1 row in set (0.01 sec)
mysql> SELECT * FROM t2;
Empty set (0.01 sec)
這是因為 SELECT
陳述式沒有參考任何表格,如輸出的 table
和 Extra
欄位中所見。下列巢狀 SELECT
也是如此:
mysql> EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS a2\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: No tables used
1 row in set, 1 warning (0.00 sec)
mysql> SHOW WARNINGS;
+-------+------+------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------+
| Note | 1249 | Select 2 was reduced during optimization |
+-------+------+------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM t2;
Empty set (0.00 sec)
但是,如果外部 SELECT
參考任何表格,最佳化工具也會執行子查詢中的陳述式,導致 t2
被修改:
mysql> EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5)) AS a2\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: <derived2>
partitions: NULL
type: system
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: a1
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
filtered: 100.00
Extra: NULL
*************************** 3. row ***************************
id: 2
select_type: DERIVED
table: NULL
partitions: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
filtered: NULL
Extra: No tables used
3 rows in set (0.00 sec)
mysql> SELECT * FROM t2;
+------+
| c1 |
+------+
| 5 |
+------+
1 row in set (0.00 sec)
衍生表格最佳化也可以用於許多相關 (純量) 子查詢。如需更多資訊和範例,請參閱第 15.2.15.7 節「相關子查詢」。