Spec-Zone .ru
спецификации, руководства, описания, API

13.2.10.8. Подзапросы в FROM Пункт

Подзапросы являются законными в a SELECT оператор FROM пункт. Фактический синтаксис:

SELECT ... FROM (subquery) [AS] name ...

[AS] name пункт обязателен, потому что каждая таблица в a FROM у пункта должно быть имя. Любые столбцы в subquery у списка выборки должны быть уникальные имена.

Ради иллюстрации предположите, что у Вас есть эта таблица:

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;

Результат: 2, '2', 4.0.

Вот другой пример: Предположите, что Вы хотите знать среднее число ряда сумм для сгруппированной таблицы. Это не работает:

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) распознается во внешнем запросе.

Подзапросы в FROM пункт может возвратить скаляр, столбец, строку, или таблицу. Подзапросы в FROM пункт не может быть связанными подзапросами, если не использующийся в пределах ON пункт a JOIN работа.

В MySQL 5.7 оптимизатор определяет информацию о полученных таблицах таким способом, для которого не происходит материализация их EXPLAIN. См. Раздел 8.13.16.3, "Оптимизируя Подзапросы в FROM Пункт (Полученные Таблицы)" .

Возможно при определенных обстоятельствах изменить табличное использование данных EXPLAIN SELECT. Это может произойти, если внешние доступы запроса, любые таблицы и внутренний запрос вызывают сохраненную функцию, которая изменяет одну или более строк таблицы. Предположите, что есть две таблицы t1 и t2 в базе данных d1, создаваемый как показано здесь:

mysql> CREATE DATABASE d1;Query OK, 1 row affected (0.00 sec)mysql> USE d1;Database changedmysql> CREATE
        TABLE t1 (c1 INT);Query OK, 0 rows affected (0.15 sec)mysql> CREATE
        TABLE t2 (c1 INT);Query OK, 0 rows affected (0.08 sec)

Теперь мы создаем сохраненную функцию f1 который изменяет t2:

mysql> DELIMITER //mysql> CREATE FUNCTION f1(p1 INT) RETURNS INTmysql>   BEGINmysql>     INSERT INTO t2
        VALUES (p1);mysql>     RETURN p1;mysql>   END //Query OK, 0 rows affected (0.01 sec)mysql> DELIMITER ;

Ссылка на функцию непосредственно в EXPLAIN SELECT не имеет никакого эффекта на t2, как показано здесь:

mysql> SELECT * FROM t2;Empty set (0.00 sec)mysql> EXPLAIN SELECT f1(5);+----+-------------+-------+------+---------------+------+---------+------+------+----------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+1 row in set (0.00 sec)mysql> SELECT * FROM t2;Empty set (0.00 sec)

Это то, потому что SELECT оператор не ссылался ни на какие таблицы, как может быть замечен в table и Extra столбцы вывода. Это также верно для вложенного следующего SELECT:

mysql> EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS
        a2;+----+-------------+-------+------+---------------+------+---------+------+------+----------------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |+----+-------------+-------+------+---------------+------+---------+------+------+----------------+|  1 | PRIMARY     | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | 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 ссылки любые таблицы, оптимизатор выполняет оператор в подзапросе также:

mysql> EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5))
        AS a2;+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+| id | select_type | table      | type   | possible_keys | key  | key_len | ref  | rows | Extra               |+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+|  1 | PRIMARY     | a1         | system | NULL          | NULL | NULL    | NULL |    0 | const row not found ||  1 | PRIMARY     | <derived2> | system | NULL          | NULL | NULL    | NULL |    1 |                     ||  2 | DERIVED     | NULL       | NULL   | NULL          | NULL | NULL    | NULL | NULL | No tables used      |+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------+3 rows in set (0.00 sec)mysql> SELECT * FROM t2;+------+| c1   |+------+|    5 |+------+1 row in set (0.00 sec)

Это также означает что EXPLAIN SELECT оператор такой как один показанный здесь может занять много времени, чтобы выполниться потому что BENCHMARK() функция выполняется однажды для каждой строки в t1:

EXPLAIN SELECT * FROM t1 AS a1, (SELECT BENCHMARK(1000000, MD5(NOW())));