派生表是一个表达式,在查询 FROM 子句范围内生成一个表。例如,SELECT 语句 FROM 子句中的子查询是派生表:
1. SELECT ... FROM (subquery) [AS] tbl_name ...
JSON_TABLE() 函数生成一个表,并提供另一种创建派生表的方法:
1. SELECT * FROM JSON_TABLE(arg_list) [AS] tbl_name ...
[AS] tbl_name 子句是必需的,因为 FROM 子句中的每个表都必须有一个名称。派生表中的任何列都必须具有唯一的名称。或者,tbl_name 后面可以跟一个用括号括起来的派生表的一系列列名:
1. SELECT ... FROM (subquery) [AS] tbl_name (col_list) ...
列名的数目必须与表的列数相同。
为了便于说明,假设有以下表:
1. CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
下面是如何在 FROM 子句中使用子查询,使用示例表:
1. INSERT INTO t1 VALUES (1,‘1‘,1.0); 2. INSERT INTO t1 VALUES (2,‘2‘,2.0); 3. SELECT sb1,sb2,sb3 4. FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb 5. WHERE sb1 > 1;
结果:
1. +------+------+------+ 2. | sb1 | sb2 | sb3 | 3. +------+------+------+ 4. | 2 | 2 | 4 | 5. +------+------+------+
下面是另一个例子:假设想知道分组表的一组和的平均值。下面的语句不起作用:
1. SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
但是,此查询会得到所需的信息:
1. SELECT AVG(sum_column1) 2. FROM (SELECT SUM(column1) AS sum_column1 3. FROM t1 GROUP BY column1) AS t1;
请注意,子查询中使用的列名(sum_column1)在外部查询中可以被识别。
派生表的列名来自其选择列表:
1. mysql> SELECT * FROM (SELECT 1, 2, 3, 4) AS dt; 2. +---+---+---+---+ 3. | 1 | 2 | 3 | 4 | 4. +---+---+---+---+ 5. | 1 | 2 | 3 | 4 | 6. +---+---+---+---+
若要显式提供列名,请在派生表名后面加上一个带圆括号的列名列表:
1. mysql> SELECT * FROM (SELECT 1, 2, 3, 4) AS dt (a, b, c, d); 2. +---+---+---+---+ 3. | a | b | c | d | 4. +---+---+---+---+ 5. | 1 | 2 | 3 | 4 | 6. +---+---+---+---+
派生表可以返回标量、列、行或表。
派生表受以下限制:
● 派生表不能包含对同一 SELECT 的其他表的引用(这种情况需要使用 LATERAL 派生表)
● 在 MySQL 8.0.14 之前,派生表不能包含外部引用。这个限制在 MySQL 8.0.14 中取消了,不是 SQL 标准的限制。例如,以下查询中的派生表 dt 包含外部查询中表 t1 的引用 t1.b:
1. SELECT * FROM t1 2. WHERE t1.d > (SELECT AVG(dt.a) 3. FROM (SELECT SUM(t2.a) AS a 4. FROM t2 5. WHERE t2.b = t1.b GROUP BY t2.c) dt 6. WHERE dt.a > 10);
查询在 MySQL 8.0.14 及更高版本中有效。在 8.0.14 之前,它生成一个错误:Unknown column ‘t1.b‘ in ‘where clause‘
优化器确定有关派生表的信息时,EXPLAIN 不需要具体化它们。
在某些情况下,使用 EXPLAIN SELECT 可能会修改表数据。如果外部查询访问某些表,而内部查询调用存储函数,更改了表中的一行或多行,则会发生这种情况。假设数据库 d1 中有两个表 t1 和 t2,以及修改 t2 的存储函数 f1,创建如下:
1. CREATE DATABASE d1; 2. USE d1; 3. CREATE TABLE t1 (c1 INT); 4. CREATE TABLE t2 (c1 INT); 5. CREATE FUNCTION f1(p1 INT) RETURNS INT 6. BEGIN 7. INSERT INTO t2 VALUES (p1); 8. RETURN p1; 9. END;
在 EXPLAIN SELECT 中直接引用函数对 t2 没有影响,如下所示:
1. mysql> SELECT * FROM t2; 2. Empty set (0.02 sec) 3. 4. mysql> EXPLAIN SELECT f1(5)\G 5. *************************** 1. row *************************** 6. id: 1 7. select_type: SIMPLE 8. table: NULL 9. partitions: NULL 10. type: NULL 11. possible_keys: NULL 12. key: NULL 13. key_len: NULL 14. ref: NULL 15. rows: NULL 16. filtered: NULL 17. Extra: No tables used 18. 1 row in set (0.01 sec) 19. 20. mysql> SELECT * FROM t2; 21. Empty set (0.01 sec)
这是因为 SELECT 语句没有引用任何表,可以在输出的 table 和 Extra 列中看到。以下嵌套 SELECT 也是如此:
1. mysql> EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS a2\G 2. *************************** 1. row *************************** 3. id: 1 4. select_type: PRIMARY 5. table: NULL 6. type: NULL 7. possible_keys: NULL 8. key: NULL 9. key_len: NULL 10. ref: NULL 11. rows: NULL 12. filtered: NULL 13. Extra: No tables used 14. 1 row in set, 1 warning (0.00 sec) 15. 16. mysql> SHOW WARNINGS; 17. +-------+------+------------------------------------------+ 18. | Level | Code | Message | 19. +-------+------+------------------------------------------+ 20. | Note | 1249 | Select 2 was reduced during optimization | 21. +-------+------+------------------------------------------+ 22. 1 row in set (0.00 sec) 23. 24. mysql> SELECT * FROM t2; 25. Empty set (0.00 sec)
但是,如果外部 SELECT 引用某些表,优化器也会执行子查询中的语句,结果是 t2 被修改:
1. mysql> EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5)) AS a2\G 2. *************************** 1. row *************************** 3. id: 1 4. select_type: PRIMARY 5. table: <derived2> 6. partitions: NULL 7. type: system 8. possible_keys: NULL 9. key: NULL 10. key_len: NULL 11. ref: NULL 12. rows: 1 13. filtered: 100.00 14. Extra: NULL 15. *************************** 2. row *************************** 16. id: 1 17. select_type: PRIMARY 18. table: a1 19. partitions: NULL 20. type: ALL 21. possible_keys: NULL 22. key: NULL 23. key_len: NULL 24. ref: NULL 25. rows: 1 26. filtered: 100.00 27. Extra: NULL 28. *************************** 3. row *************************** 29. id: 2 30. select_type: DERIVED 31. table: NULL 32. partitions: NULL 33. type: NULL 34. possible_keys: NULL 35. key: NULL 36. key_len: NULL 37. ref: NULL 38. rows: NULL 39. filtered: NULL 40. Extra: No tables used 41. 3 rows in set (0.00 sec) 42. 43. mysql> SELECT * FROM t2; 44. +------+ 45. | c1 | 46. +------+ 47. | 5 | 48. +------+ 49. 1 row in set (0.00 sec)
这也意味着像这里所示的 EXPLAIN SELECT 语句可能需要执行很长时间,因为在 t1 中,BENCHMARK() 函数对每一行执行一次:
1. EXPLAIN SELECT * FROM t1 AS a1, (SELECT BENCHMARK(1000000, MD5(NOW())));
官方网址: https://dev.mysql.com/doc/refman/8.0/en/derived-tables.html
MySQL的SQL语句 - 数据操作语句(13)- 子查询(9)
标签:ring 相同 row sim 列表 turn ssi ofo war
查看更多关于MySQL的SQL语句 - 数据操作语句(13)- 子查询(9)的详细内容...