前言

前面的一篇文章写了下数据库设计和SQL语句基础,里面都是简单的增删改查,而且对最重要的查(Retrieve)也没有深入研究,实在是罪过,那么本文就sql复杂的查询语句进行探讨,也是当作一个记录好了

18.1.9更新:
推荐一本书:SQL学习指南,之前那篇文章还是不太全面,而且更多也只是停留在独立相对没有那么复杂的SQL上,而这一本则是更加全面地SQL扫盲,并且教你如何组合你的SQL

Example I

假设我们现在有张这样的成绩表grade

name class score
光头 语文 9
吴克 语文 100
光头 物理 99
吴克 物理 7
光头 体育 100
吴克 体育 5

Question:

求不及格(score<60)科目大于等于2门的那个人的平均分,一条sql解决?

Answer:

SELECT name,AVG(score) 
FROM grade
WHERE name IN (SELECT name FROM grade WHERE score<60 GROUP BY name HAVING COUNT(score)>=2)
GROUP BY name;

现在我们来一点点理解Answer:

  • 1 首先要知道sql执行顺序是:

FROM(JOIN...ON)=>WHERE(IN)=>GROUP BY=>HAVING=>WINDOW FUNCTION=>SELECT=>DISTINCT=>UNION(ALL)/INTERSECT/EXCEPT=>ORDER BY=>OFFSET =>LIMIT/FETCH/TOP
REF:Beginner’s Guide to the True Order of SQL Operations

  • 2 FROM grade:
name class score
光头 语文 9
吴克 语文 100
光头 物理 99
吴克 物理 7
光头 体育 100
吴克 体育 5
  • 3 WHERE name IN (SELECT name FROM grade WHERE score<60 GROUP BY name HAVING COUNT(score)>=2)
    • 先搞括号内
    • 3-1FROM score,我们可以得到原来的表如下
    name class score
    光头 语文 9
    吴克 语文 100
    光头 物理 99
    吴克 物理 7
    光头 体育 100
    吴克 体育 5
    • 3-2WHERE score<60,我们可以筛出得分小于60的项的表,如下
    name class score
    光头 语文 9
    吴克 物理 7
    吴克 体育 5
    • 3-3GROUP BY name,相同姓名归一组。GROUP BY简单来说是建立组
      注意:截图中sn为name,cn为class,sc为score,下同

    sn为name,cn为class,sc为score

    • 3-4HAVING COUNT(score)>=2,HAVING的作用和WHERE很像都是筛选,不过WHERE不能带聚合函数的(比如SVG,SUM,COUNT等等),HAVING是用来筛选组的,所以往往和GROUP BY配合出现

    这里写图片描述

    • 3-5SELECT name,根据上面HAVING筛选结果自然就只有吴克
    • 再搞括号外的
    • 3-6WHERE name IN (吴克),故name的取值只能是吴克,最后得到:
    name class score
    吴克 语文 100
    吴克 物理 7
    吴克 体育 5
  • 4 GROUP BY name 这里写图片描述

  • 5 最后SELECT name,AVG(score),我们就可以求得我们这位挂课数目在2门以上的这位吴克同学的平均分了
name AVG(score)
吴克 37.3333

Reference:
[1]十步完全理解 SQL
[2]可以这样去理解group by和聚合函数