https://blog.rjmetrics.com/2008/10/28/correlated-subqueries-in-mysql/

http://www.mysqltutorial.org/mysql-subquery/

SQL是关系数据库中非常基础同时也是非常重要的知识,虽然比如类似Laravel的后端开发类库提供了ORM抽象数据类封装掉了一部分简单的sql查询,因此很多时候我们无需关系sql的具体细节,便能非常快速地开发出自己的后端应用来,但是一旦涉及到相对比较复杂的关系时我们还是不得不再去求助于sql。本博作为鸡年新年刚过,起个开端,不断记录积累本人在sql学习中觉得重要的点点滴滴,学习资源,备忘的同时,也希望给有缘人以帮助

SQL Subselect and correlated subquery

subquery就是被括号所包围的一个被嵌入到另外一个SQL statement的statement。而包含这个subquery的statement我们通常称为outer query, subquery本身被成为inner query.

A sub query is a nested query where the results of one query can be used in another query via a relational operator or aggregation function

和subquery有关的规则:

1. 一个subquery必须出现在()括号中;

2. 你可以在一个query中嵌入另外一个subquery,这个层级没有限制;

3. 如果outer query对subquery期待(或者说引用)一个single value或者一系列value,那么subquery只能使用one expression or column name in its select list; (a subquery can have only one column in the select clause if used in where clause)

4. orderby clause不允许在subquery中出现

5. subquery可以被用在where, having, from和select clause中

select t1.* from table1 t1 where t1.id not in (select t2.id from table2 t2): non-corelated subquery

http://www.geeksengine.com/database/subquery/return-single-value.php

.在大多数情况下,我们可以非常轻松地以JOIN语句来完全实现一个子select语句的功能(或者相反)。但是很多时候,和join方法相比,subquery来得更加通俗易懂,符合逻辑。比如像IN, ANY这些关键字的使用就往往使得语句更易理解和容易被分解。作为一个例子,我们来看下面问题的query语句:

" 列出所有在NJ州的客人名单"

select Name from Customers where CustomerID = ANY ( select CustomerID from AddressBook where state = 'NJ')

在这个例子中,括号中的黑体部分就是一个subquery.

这个subquery被我们称做"Non-correlated" subquery,原因是你可以单独执行这条select语句来得到一个合乎逻辑的正确的结果集.在这个例子中,隔离的subquery可以产生一个来自NJ州的客户名单列表。

然而,相对于这种Non-correlated就有一种Correlated subquery,这种子查询包含着outer query的value的引用,因此无法脱离outer query而单独执行

我们举一个典型的查询例子:

select * from t1 where column1 = ANY ( SELECT column1 from t2 where t2.column2 = t1.column2)

注意在这个例子中,t1表虽然并未在subquery的from clause所指出但是却被subquery中的where clause所引用,t1表只存在于outer query语句中,如果你直接执行这个隔离的subquery,你将由于无法找到t1表而出错。

和他们的non-correlated subquery例子,correlated subquery不允许在from clause中出现。这个关键规则,在mysql refman文档中甚至没有提及,显著地降低了correlated subquery可以应用的范围。

那么,如果一个correlated subquery不能在query的from clause中使用,那么到底可以用在哪里呢?

正如我们在例子中看到的一样,correlated subquery可以在where clause中使用,同时就像non-correlated subquery一样,它也可以在having clause或select clause中使用。

这些可以被允许出现的clause有什么共同之处呢?答案可以说非常简单:他们被用在数据已经被拉出来之后(after data is pulled),要么用于限制被选中的rows或者修改哪些columns被显示出来!换句话说,如果你将subquery全部拉出去,你也可以获得完全正确逻辑的结果(仅仅少掉subquery部分的逻辑)

比如,我们看看下面两个clause,一个correlated subquery可能会对他们的query结果有什么影响:

首先,我们看看where clause的情况:

select Name from dogs where age>=5

在没有where clause的情况下,query依然可以正确运行并且返回每一条狗的名字。然而,where clause的作用是仅仅剔除了那些年龄小于5的row

类似地,我们再看看select clause的情况下:

select Name, age*7 as humanage from dogs where age >=5

就算没有age*7, 这个query也能够获取和上面的query相同结果的结果集。然而,在select clause中增加这个expressio则会在最后的结果集中的每一row中增加特定的信息。

上面两个例子有什么共性呢?无论是在where clause的情况还是select expression的情况都是运行于一个除了where clause和select expression(age*7)外的其他query返回的结果上,他们只能limit rows(where)或者增加columns(select).无一例外,在where和select中出现的expression都是针对如果没有他们时的query返回的结果集中的每一行来evaluated的.

所以,现在我们可以问这样一个问题:

如果我们将where comparison或者select expression替换成一个correlated subquery结果会是怎样?答案是相同的共性: subquery执行于将其剔除掉后的query返回的结果集中的每一行。这样,对每一条row record,你可以在outer from clause中引用任何table的任何column的value. 看看下面的corelated subquery:

select Name from dogs d where (select max(HaircutDate) from haircuts h where h.Name = d.Name) < '2008-09-01'

这个query返回每一条自从2008年9月1日未理过发的狗的名字。当这个query被执行时,在where cluase中的subqury对于每一条剔除subquery外的其他query语句结果集中的每一条row都要被执行一遍。也就是说,如果在dogs表中有20个dogs记录,mysql将执行这个subquery 20遍,针对每row每次运行时都将d.Name使用该row的dog name来替换后执行。

再看下面的查询,我们将使用在select clause中的subquery来获取每一条狗的最近harcut date:

select Name, (select max(HaircutDate) from haircuts h where h.Name = d.Name) as LastHaircut from dogs d

和普通的驻留于where和select clause中的subquery一样,corelated subquery被设计为返回一系列标量值(而不是一表格的结果),或者有时为一行的值。 subquery-related keywords比如IN, ANY, SOME, EXISTS仅仅返回true或者false,而这非常适合使用where clause subquery

你也可以在UPDATE, DELETE STATEMENTS中的where clause中使用corelated subquery以便narrow down哪些row将可以被这条statement所影响。

下面的correlated query执行过程:

select distinct a.ProductID, 
a.UnitPrice as Max_unit_price_sold
from order_details as a
where a.UnitPrice =
(
select max(UnitPrice)
from order_details as b
where a.ProductID = b.ProductID
)
order by a.ProductID;
    1. The outer query passes a value for ProductID to the subquery. It takes place in the WHERE clause in the subquery [ where a.ProductID = b.ProductID ]

    2. The subquery uses this passed-in ProductID value to look up the max unit price for this product
      [ select max(UnitPrice) from order_details ]

    3. When the max unit price for the product is found in the subquery, it's returned to the outer query.

      The outer query then uses this max unit price in its WHERE clause to match unit price in order_details table for this product [ where a.UnitPrice = ]

      When the row is found, query engine temporarily holds the row in memory. It's guaranteed that a row will be found because both outer query and subquery use the same table - order_details.

    4. The query engine then moves onto next row in the order_details table and repeat Step 1 to 3 again for the next product.

    5. When all products in order_details have been evaluated, it does a sorting and then returns the query result.

mysql查询优化best practice

1. 只获取app需要的row(使用where clause)

2. 只获取app需要的column,避免使用select *

3. 避免多次获取相同的数据,应该使用app的cache机制缓存需要多次使用到的数据

4. 使用db的orderby in the select clause rather than app

5. 将大的delete, update, insert query分解成多个小的query

6. 所有的column使用适当的数据类型, smaller columns总是更快;

7. mysql query cache是case sensitive的

8. 将所有where clause中的column都增加index (具体要看explain命令查看是否用到对应的index)

9. 将join中用到的column都做index

10. table order对于innder join clause是没有关系的;

11. 使用limit clause来实现pagination 逻辑;

mysql查询执行顺序:

SQL JOIN:

SQL JOIN combines columns from two or more tables in a single result set.

inner join, outer join, cross join, self join, natural join

inner join返回rows when there is at least one match in both the tables.

应该避免ambiguity,通过alias table 的方法;

select t1.*, t2.* from table1 t1 inner join table2 t2 on t1.id = t2.id

left outer join returns all the rows from the left table with the matching rows from the right table, if there are no columns matching in the right table, it returns null values

right outer join returns all the rows from the right table with the matching rows from the left table, if there are no columns matching in the left table, it returns null values

full outer join: 由于mysql并不支持full outer join,因此我们必须使用left outer join和right outer join以及union来模拟full outer join

joins vs subquery

joins can include any columns from joining tables in the select clause

joins easy to read and more intuitive;

subquery can pass the aggregate values to the main query

select fm.title, cat.name,dt.countofcategory from film fm

inner join film_category fc on fc.film_id = fm.film_id

inner join category cat on cat.category_id = fc.category_id

inner join(

select count(*) as countofcategory, fc.category_id from film_category fc

group by fc.category_id) dt on dt.category_id  = fc.category_id

sql查询学习和实践点滴积累的更多相关文章

  1. Hive SQL 语法学习与实践

    Hive 介绍 Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构化的数据文件映射为一张数据库表,并提供 ...

  2. [强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)

    原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天 ...

  3. 大数据技术之_19_Spark学习_03_Spark SQL 应用解析 + Spark SQL 概述、解析 、数据源、实战 + 执行 Spark SQL 查询 + JDBC/ODBC 服务器

    第1章 Spark SQL 概述1.1 什么是 Spark SQL1.2 RDD vs DataFrames vs DataSet1.2.1 RDD1.2.2 DataFrame1.2.3 DataS ...

  4. SQL反模式学习笔记18 减少SQL查询数据,避免使用一条SQL语句解决复杂问题

    目标:减少SQL查询数据,避免使用一条SQL语句解决复杂问题 反模式:视图使用一步操作,单个SQL语句解决复杂问题 使用一个查询来获得所有结果的最常见后果就是产生了一个笛卡尔积.导致查询性能降低. 如 ...

  5. 01.基础架构:一条SQL查询语句是如何执行的?学习记录

    01.基础架构:一条SQL查询语句是如何执行的?学习记录http://naotu.baidu.com/file/1c8fb5a0f2497c3a2655fed89099cb96?token=ff25d ...

  6. MySQL与OLAP:分析型SQL查询最佳实践探索

    搞点多维分析,糙快猛的解决方式就是使用ROLAP(关系型OLAP)了.数据经维度建模后存储在MySQL,ROLAP引擎(比方开源的Mondrian)负责将OLAP请求转化为SQL语句提交给数据库.OL ...

  7. SQL:查询学习笔记

    SQL 查询命令 SELECT 语法 SELECT "column_name" FROM "table_name"; 返回一列 SELECT Username ...

  8. mysql数据库系统学习(一)---一条SQL查询语句是如何执行的?

    本文基于----MySQL实战45讲(极客时间----林晓斌 )整理----->https://time.geekbang.org/column/article/68319 一.第一节:一条sq ...

  9. hibernate 5原生sql查询测试学习代码

    基本查询 import java.util.List; import org.hibernate.SQLQuery; import org.hibernate.Session; import org. ...

随机推荐

  1. net与树莓派的情缘(二)

    虽然我们可以很方便的通过ssh譬如putty或者vnc连接操控树莓派,但是毕竟树莓派资源没那么高,在上面编程,调试要吃力的多.所以还是想在pc上编程上传到树莓派或者最好,文件共享,可以直接读写共同的文 ...

  2. 【JAVA-WEB】在url上追加sessionid

    HttpSession session = request.getSession(); url = url+";jsessionid="+session.getId();

  3. redis 持久化之 rdb 快照持久化

    解释1: 虽然redis是单进程,但是它有一个单独的子进程进行rdb操作,为了保证的数据的一致性,当进行rdb操作失败的时候,主进程就停止写入 所以才有了stop-write-on-bgsave-er ...

  4. JS 开发者必须知道的十个 ES6 新特性

    这篇文章会给你简单介绍一下ES6.如果你还不知道什么是ES6的话,它是JavaScript一个新的实现,如果你是一个忙碌的JavaScript开发者(但谁不是呢),那么继续读下去吧,看看当今最热门的语 ...

  5. XML的基本概念和Android下的使用

    1. XML的基本概念 1. 什么是XML: 1). XML是指可扩展标记语言(eXtensible Markup Language),它是一种标记语言,很类似HTML.它被设计的宗旨是表示数据,而非 ...

  6. 通过开机广播(broadcast)通知应用

    1. 概念 开机的时候,系统会发送一则广播,所有有标记的应用(通过广播接收者)都会获取得到,然后可以通过广播接收者去处理一些事情,比如启动该应用,或者处理数据: 代码:https://github.c ...

  7. C# Lambda表达式详细总结

    (一)输入参数 在Lambda表达式中,输入参数是Lambda运算符的左边部分.它包含参数的数量可以为0.1或者多个.只有当输入参数为1时,Lambda表达式左边的一对小括弧才可以省略.输入参数的数量 ...

  8. Node.js创建第一个应用

    在我们创建 Node.js 第一个 "Hello, World!" 应用前,让我们先了解下 Node.js 应用是由哪几部分组成的: 引入 required 模块:我们可以使用 r ...

  9. 禁止选中页面内容-兼容ie、firefox、chrome

    使用js禁止用户选中网页上的内容,IE及Chrome下的方法一样.使用onselectstart, 比如: 在body中加入<body onselectstart="return fa ...

  10. jQuery选择器,外加例子讲解

    jQuery选择器的优势: (1) 代码更简单(2) 支持CSS1到CSS3选择器(3) 完善的处理机制 jQuery选择器的分类 (1) 基本选择器 基本选择器是jQuery中使用最多的选择器,它又 ...