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. 二、利用继承修改OPENERP 的一个模块

    问题记录1: No modules named 'xx' 原因: __init__.py 文件命名错误! 问题记录2: XMLSyntaxError: Attribute name redefined ...

  2. (转).NET技术大系概览 (迄今为止最全的.NET技术栈)

    前言 .Net推出13年了,Visual Studio 2015 / .NET Framework 4.6昨天也发布了. 从2002年的.NET 1.0开始,1.1,2.x,3.x,4.x,每个新版本 ...

  3. 什么是Java代码的编译与反编译?(转)

    转自:http://java.tedu.cn/ask/203119.html Java代码的编译与反编译 一.什么是编译 1.利用编译程序从源语言编写的源程序产生目标程序的过程. 2.用编译程序产生目 ...

  4. IE8下不识别indexOf的问题

    1.为Array原型添加indexOf方法(如果学过面向对象,相当于给Array类添加实例方法),方法体如下: //添加数组IndexOf方法 if (!Array.prototype.indexOf ...

  5. JS写游戏

    最近在看萧井陌的视频.感觉一些东西挺有意思的,尤其是解决问题的过程,以及一个好程序应该改进的地方. 萧大的GITHUB:github.com/guaxiao/gua.game.js 视频:https: ...

  6. FS及CacheFS类解读

    Javac中有FSInfo与CacheFSInfo两个类,CacheFSInfo继承了FSInfo类,这两个类的主要功能就是通过map缓存Jar文件,核心代码如下: private Map<Fi ...

  7. unity字库精简

    有2种办法,具体看情况使用 1.unity自带功能 选择放入的字体,修改Character项为"Custom set",接着出现Custom Chars中输入你想使用的字符串,字符 ...

  8. [PY3]——内置数据结构(5)——字符串编码

    py2和py3中关于字符串的最大区别? python2中只有 unicode类型 而python3中有 string bytes两种类型 关于string和bytes的区分? 1.str是文本序列.b ...

  9. 对数几率回归法(梯度下降法,随机梯度下降与牛顿法)与线性判别法(LDA)

    本文主要使用了对数几率回归法与线性判别法(LDA)对数据集(西瓜3.0)进行分类.其中在对数几率回归法中,求解最优权重W时,分别使用梯度下降法,随机梯度下降与牛顿法. 代码如下: #!/usr/bin ...

  10. [转]emailjs-smtp-client

    本文转自:https://github.com/emailjs/emailjs-smtp-client/blob/master/README.md SMTP Client SMTP Client al ...