MySQL 子查询(三) 派生表、子查询错误

  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‘,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)可以在外部查询中被识别。

  派生表可以返回一个标量、一列数据,一行数据或者一个表。

  派生表受这些限制的约束:

  • 派生表不能是相关子查询;
  • 派生表不能包含对同一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的目标表。

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

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

原文地址:https://www.cnblogs.com/bigbigbigo/p/10965171.html

时间: 2024-10-11 02:12:10

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

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

MySQL-子查询 MySQL子查询是嵌套在另一个查询中的查询. MySQL子查询还可以嵌套在另一个子查询中. MySQL子查询称为内部查询,而包含子查询的查询称为外部查询. 查询返回在位于美国(USA)的办公室工作的员工. SELECT lastName, firstName FROM employees WHERE officeCode IN (SELECT officeCode FROM offices WHERE country = 'USA'); MySQL-派生式 派生式和子查询通常

Yii的Relational Active Record三张表连接查询

需求如下: 查询book表信息,同时关联entitystags表,以entitystags的字段eid关联book的主键,再关联查询tags表,以entitystags表的tid字段关联tags表的主键id 同时读出这三张表的信息来,在Yii可以如下处理,先在relations方法中声明三张表的关系,在控制器中,以with表明渴求式调用,即可,代码如下: 在book的model文件中声明关系: public function relations(){ return array( 'entitys

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

-------------------------------------day3------------ --添加多行数据:------INSERT [INTO] 表名 [(列的列表)] --SELECT UNION --SELECT 'HAHA',1,32--UNION ALL --全部显示/显示重复数据 即使集合相同--UNION---------将查询的两个结果集合并.结构必须一致 -->常见面试题 --SELECT 'HEHE',2,33------将查询结果添加到列表中(子查询)IN

MySQL 子查询与多表联合查询

子查询:就是一个查询的结果作为另一个查询的数据源或者条件. 如何查询出工资最大的人的姓名? mysql> select max(sal) from emp; --查询出工资最大值 +----------+ | max(sal) | +----------+ | 5000.00 | +----------+ 1 row in set (0.00 sec) mysql> select ename,sal from emp where sal = (select max(sal) from emp)

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

序言 1.MySQL表操作(创建表,查询表结构,更改表字段等), 2.MySQL的数据类型(CHAR.VARCHAR.BLOB,等), 本节比较重要,对数据表数据进行查询操作,其中可能大家不熟悉的就对于INNER JOIN(内连接).LEFT JOIN(左连接).RIGHT JOIN(右连接)等一些复杂查询. 通过本节的学习,可以让你知道这些基本的复杂查询是怎么实现的,但是建议还是需要多动手去敲,虽然理解了什么是内连接等,但是从理解到学会,是完全不一样的感觉. --WH 一.单表查询 1.1.查

mysql 三个表连接查询

权限表(permission)10 字段名称 类型 约束 描述 authorityid integer Pk not null 权限流水号id    PK userNameId int not null 用户名id   FK functionid integer Not null 功能 id    FK lookPermission int not null 浏览 addPermission int not null 添加 editPermission int not null 编辑 delet

MySQL中的基本多表连接查询 转自脚本之家(作者:真实的归宿)

一.多表连接类型 1. 笛卡尔积(交叉连接) 在MySQL中可以为CROSS JOIN或者省略CROSS即JOIN,或者使用','  如: 由于其返回的结果为被连接的两个数据表的乘积,因此当有WHERE, ON或USING条件的时候一般不建议使用,因为当数据表项目太多的时候,会非常慢.一般使用LEFT [OUTER] JOIN或者RIGHT [OUTER] JOIN 2.   内连接INNER JOIN 在MySQL中把I SELECT * FROM table1 CROSS JOIN tabl

oracle数据库的高级查询方法 多表联合查询

oracle查询 一,简单查询 order by 1,2 select t.sno, t.sname, t.ssex from STUDENT t order by 1,2,3 group by 增强版 SELECT p.toma, p.ptype, SUM(p.lastcou) FROM product p GROUP BY rollup(p.toma, p.ptype) 二,高级查询(多表连接查询) 笛卡尔积的概念: 所谓笛卡尔积,通俗点说就是指包含两个集合中任意取出两个元素构成的组合的集合

Oracle - 查询语句 - 多表关联查询

/* SQL语句的历史版本 SQL89 比较多 SQL92 SQL99 多表关联查询 笛卡尔积 等值关联查询 非等值关联查询 左外连接 右外连接 全外连接 自连接 */ ----------------------------------92语法 --查询部门名称和员工名称(两张表的关联没有任何的约束条件) SELECT * FROM EMP; SELECT * FROM DEPT; SELECT * FROM SALGRADE; SELECT * FROM EMP,DEPT; SELECT *

单表查询、多表查询、虚拟表连接查询

  单表查询,以下面这个表为例:+----+------------+--------+-----+------------+----------------------------+--------------+------------+--------+-----------+| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id |+----+------------+-