From MySQL 5.7 ref:13.2.10.8 Derived Tables

八、派生表

  派生表是一个表达式,用于在一个查询的FROM子句的范围内生成表。

  例如,在一个SELECT查询的FROM子句中的子查询,就是一个派生表。

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

  [AS] tbl_name子句是必需的,因为FROM子句中的每个表都必须具有名称。且派生表中的任何列都必须具有唯一名称。

  为了便于说明,假设现在有这样一个表:

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

  使用示例表,在FROM子句中使用子查询:

INSERT INTO t1 VALUES (1,'',1.0);
INSERT INTO t1 VALUES (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的限制,而不是SQL标准的限制。

  See Section 8.2.2.4, “Optimizing Derived Tables and View References with Merging or Materialization”.

  在某些情况下,使用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: SIMPLE
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)

  这也意味着EXPLAIN SELECT语句(例如此处显示的语句)可能需要很长时间才能执行,因为会对t1中的每一行执行一次BENCHMARK()函数:

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

九、子查询错误

  有些错误仅适用于子查询。本节介绍它们。

  9.1 不被支持的子查询语法

ERROR 1235 (ER_NOT_SUPPORTED_YET)
SQLSTATE = 42000
Message = "This version of MySQL doesn't yet support
'LIMIT & IN/ALL/ANY/SOME subquery'"

  这意味着MySQL不支持以下形式的语句:

SELECT * FROM t1 WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1)

  

  9.2 子查询中的列数不正确

ERROR 1241 (ER_OPERAND_COL)
SQLSTATE = 21000
Message = "Operand should contain 1 column(s)"

  这个错误会在以下情况下发生:

SELECT (SELECT column1, column2 FROM t2) FROM t1;

  如果目的是行比较,则可以使用返回多个列的子查询。而在其他上下文中,子查询必须是标量操作数。参考前面的第五小节。

  自己的试验如下(student表中有12行数据):

mysql> select ( select SId from sc) from student;
ERROR 1242 (21000): Subquery returns more than 1 row select (select SId,CId from sc) from student;
ERROR 1241 (21000): Operand should contain 1 column(s) mysql> select ( select distinct SId from sc where SId="01") from student;
+-----------------------------------------------+
| ( select distinct SId from sc where SId="01") |
+-----------------------------------------------+
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
| 01 |
+-----------------------------------------------+
12 rows in set (0.00 sec)

  9.3 子查询中的行数不正确

ERROR 1242 (ER_SUBSELECT_NO_1_ROW)
SQLSTATE = 21000
Message = "Subquery returns more than 1 row"

  对于子查询必须最多返回一行但返回多行的语句,会发生此错误。参考以下示例:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

  如果SELECT column1 FROM t2只返回一行,则前一个查询将起作用。如果子查询返回多行,则会发生错误1242。

  这种情况下,可以这么修改:

SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);

  9.4 子查询中的表使用不正确:

Error 1093 (ER_UPDATE_TABLE_USED)
SQLSTATE = HY000
Message = "You can't specify target table 'x'
for update in FROM clause"

  当一个语句尝试修改表,而这个语句的子查询却从同一个表执行SELECT操作:

UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);

  您可以在UPDATE语句中使用子查询进行赋值,因为子查询在UPDATE和DELETE语句以及SELECT语句中都是合法的。但是子查询的FROM子句中不是出现UPDATE的目标表。

  对于事务存储引擎,子查询失败会导致整个语句失败。

  对于非事务性存储引擎,将保留在遇到错误之前进行的数据修改。

MySQL 子查询(三) 派生表、子查询错误的更多相关文章

  1. MySQL之多表查询一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习

    MySQL之多表查询 阅读目录 一 介绍 二 多表连接查询 三 符合条件连接查询 四 子查询 五 综合练习 一 介绍 本节主题 多表连接查询 复合条件连接查询 子查询 首先说一下,我们写项目一般都会建 ...

  2. MySQL-子查询,派生表,通用表达式

    MySQL-子查询 MySQL子查询是嵌套在另一个查询中的查询. MySQL子查询还可以嵌套在另一个子查询中. MySQL子查询称为内部查询,而包含子查询的查询称为外部查询. 查询返回在位于美国(US ...

  3. 010.简单查询、分组统计查询、多表连接查询(sql实例)

    -------------------------------------day3------------ --添加多行数据:------INSERT [INTO] 表名 [(列的列表)] --SEL ...

  4. Mybatis-plus多表关联查询,多表分页查询

    学习plus真的觉得写代码真的越来越舒服了.昨天开始接触吧,只要学会了多表关联查询.plus就能随意搭配使用了. 关于怎么搭建的就自行了去研究了哦.这里直接进入主题. 我用的是springboot+m ...

  5. MySQL子查询,派生表和通用表达式

    一:子查询 1.介绍 在另一个查询(外部查询)中嵌套另一个查询语句(内部查询),并使用内部查询的结果值作为外部查询条件. 2.子查询在where中 SELECT customerNumber, che ...

  6. MySQL(三) 数据库表的查询操作【重要】

    序言 1.MySQL表操作(创建表,查询表结构,更改表字段等), 2.MySQL的数据类型(CHAR.VARCHAR.BLOB,等), 本节比较重要,对数据表数据进行查询操作,其中可能大家不熟悉的就对 ...

  7. MySQL--详细查询操作(单表记录查询、多表记录查询(连表查询)、子查询)

    一.单表查询 1.完整的语法顺序(可以不写完整,其次顺序要对) (不分组,且当前表使用聚合函数: 当前表为一组,显示统计结果 ) select distinct [*,查询字段1,查询字段2,表达式, ...

  8. mysql 三个表连接查询

    权限表(permission)10 字段名称 类型 约束 描述 authorityid integer Pk not null 权限流水号id    PK userNameId int not nul ...

  9. mysql三张表关联查询

    三张表,需要得到的数据是标红色部分的.sql如下: select a.uid,a.uname,a.upsw,a.urealname,a.utel,a.uremark, b.rid,b.rname,b. ...

  10. Mysql数据库常规操作(建表、查询)

    一.表单操作 1-1.创建表 create table tb_name( id in primary key auto_increment);    1-2.查看表 desc table_name; ...

随机推荐

  1. git 删除目录及子目录下的同名文件

    find . -name ".git" | xargs rm -Rf find . -name ".gitignore" | xargs rm -Rf

  2. 服务器(Linux)上运行python总结

    跑实验换了几次服务器了,每次遇到相似问题都要重新百度,而且每次百度搜索出的顺序都不一样,又得重新找半天,这次把遇到的问题都总结一下. 1.准备 PuTTY和FileZilla FileZilla使用F ...

  3. libmidas.so.2

    libmidas.so.2 libmidas.so.2文件,使DATASNAP FOR LINUX中间件,支持OleVariant格式的序列,使TDataSetProvider+TClientData ...

  4. 咏南中间件D7客户端演示

    咏南中间件D7客户端演示 咏南中间件MORMOT(http.sys)支持D6.D7等老版本开发客户端.客户端使用TClientDataSet内存表控件,数据序列使用TynSerial类.

  5. Vue引入远程JS文件

    问题 最近在使用 Vue 做东西,用到钉钉扫描登录的功能,这里需要引入远程的 js 文件,因为 Vue 的方式跟之前的不太一样,又不想把文件下载到本地应用,找了一下解决的方法,貌似都需要引入第三方的库 ...

  6. <javaScript>通过getElementsByTagName获取标签的class值

    console.log(p[1].id); console.log(p.item(1).id); console.log(p[2].getAttribute("class")); ...

  7. C# 使用Task执行异步操作

    为什么要使用 Task Task 和 Thread 区别 Task 介绍 Task 简单实现 Task 执行状态 为什么要使用 Task 线程是创建并发的底层工具,因此具有一定的局限性. 没有简单的方 ...

  8. Qt编写控件属性设计器8-网络采集

    一.前言 上一篇文章已经打通了数据源之一的串口采集,这次要说的是网络采集,网络通信目前用的最多的是三种,TCP/UDP/HTTP,其中tcp通信又包括了客户端服务端两种,tcp通信才用了多次握手机制不 ...

  9. python 中的一些基础算法:递归/冒泡/选择/插入

    递归算法 如果一个函数包含了对自己的调用,那么这个函数就是递归的. 比如我们计算下1-7乘法的计算: def func(n): if n ==1 : return 1 return n*func(n- ...

  10. Python检查数组元素是否存在类似PHPisset()方法

    Python检查数组元素是否存在类似PHP isset()方法 sset方法来检查数组元素是否存在,在Python中无对应函数,在Python中一般可以通过异常来处理数组元素不存在的情况,而无须事先检 ...