本节讨论派生表的总体特性。有关由 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
)在外部查询中得到识别。
派生表的列名来自其 SELECT 列表。
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 节,“相关子查询”。