#### 13.2.11.8 派生表

[](<>)[](<>)[](<>)

本节讨论派生表的一般特征。有关前面的横向派生表的信息`侧`关键词，见[第 13.2.11.9 节，“横向派生表”](lateral-derived-tables.html).

派生表是在查询范围内生成表的表达式`从`条款。例如，一个子查询[`选择`](select.html)陈述`从`子句是派生表：

```
SELECT ... FROM (subquery) [AS] tbl_name ...
```

这[`JSON_TABLE()`](json-table-functions.html#function_json-table)函数生成一个表并提供另一种创建派生表的方法：

```
SELECT * FROM JSON_TABLE(arg_list) [AS] tbl_name ...
```

这`[作为] *`tbl_name`*`子句是强制性的，因为一个表中的每个表`从`子句必须有名称。派生表中的任何列都必须具有唯一的名称。或者，*`tbl_name`*后面可以跟一个带括号的派生表列的名称列表：

```
SELECT ... FROM (subquery) [AS] tbl_name (col_list) ...
```

列名数必须与表列数相同。

为了便于说明，假设您有这个表：

```
CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
```

以下是如何在`从`子句，使用示例表：

```
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.html)（用一个`侧`派生表；看[第 13.2.11.9 节，“横向派生表”](lateral-derived-tables.html)）。

-   在 MySQL 8.0.14 之前，派生表不能包含外部引用。这是 MySQL 8.0.14 中取消的 MySQL 限制，而不是 SQL 标准的限制。例如，派生表`dt`在以下查询中包含参考`t1.b`到桌子上`t1`在外部查询中：

    ```
    SELECT * FROM t1
    WHERE t1.d > (SELECT AVG(dt.a)
                    FROM (SELECT SUM(t2.a) AS a
                          FROM t2
                          WHERE t2.b = t1.b GROUP BY t2.c) dt
                  WHERE dt.a > 10);
    ```

    该查询在 MySQL 8.0.14 及更高版本中有效。在 8.0.14 之前，它会产生错误：`'where 子句'中的未知列't1.b'`

    优化器以如下方式确定派生表的信息：[`解释`](explain.html)不需要实现它们。看[第 8.2.2.4 节，“通过合并或实现优化派生表、视图引用和公用表表达式”](derived-table-optimization.html).

    在某些情况下，使用[`解释选择`](explain.html)修改表数据。如果外部查询访问任何表并且内部查询调用更改表的一行或多行的存储函数，则可能发生这种情况。假设有两个表`t1`和`t2`在数据库中`d1`, 和一个存储函数`f1`修改`t2`，创建如下所示：


```
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.html)对没有影响`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.html)声明没有引用任何表，如在`桌子`和`额外的`输出的列。以下嵌套也是如此[`选择`](select.html)：

```
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.html)引用任何表，优化器也会执行子查询中的语句，结果是`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)
```

派生表优化也可以用于许多相关（标量）子查询（MySQL 8.0.24 和更高版本）。有关更多信息和示例，请参阅[第 13.2.11.7 节，“相关子查询”](correlated-subqueries.html).
