Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


15.2.15.8 派生表

本节讨论派生表的总体特征。关于以LATERAL关键字前置的派生表,请参阅第15.2.15.9节,“Lateral Derived Tables”

派生表是一个在查询FROM子句的范围内生成表的表达式。例如,一个SELECT语句中的子查询是一个派生表:

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 |
+---+---+---+---+

派生表可以返回标量、列、行或表。

派生表受以下限制:

优化器根据派生表的信息,EXPLAIN 不需要将其物化。见第10.2.2.4节,“Optimizing Derived Tables, View References, and Common Table Expressions with Merging or Materialization”

在某些情况下,使用EXPLAIN SELECT可能会修改表数据。这可以发生在外层查询访问任何表,而内层查询调用存储函数,该函数改变一个或多个表的行数。假设数据库 中有两个表 t1t2t2的存储函数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语句没有引用任何表,可以在输出的tableExtra列中看到。这也适用于以下嵌套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节,“相关子查询”