点此访问在线练习平台,暂只支持电脑端访问
反馈建议请点此

水平学习SQL

在垂直学习中,我们学习了SQL的基础语法,包括SELECT、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT等。接下来,我们将对每种SQL子句进行扩展,详细介绍每种子句的用法。

SELECT

SELECT部分是SQL中最重要的部分,用于查询数据。在垂直学习章节中,我们已经学习了SELECT的基础用法,包括查询所有列、查询部分列、基本的查询函数等。接下来将详细介绍SELECT的更多用法,大体分为函数、列的重命名两个方面。

函数

在SELECT部分,我们可以对返回的结果集进行处理。这样的处理操作我们称之为函数。
在SQL中有很多函数,用于对返回的结果集进行处理,例如MIN、MAX、DISTINCT、COUNT、SUM、AVG等。
以下我们将介绍这些函数的用法。

MIN

MIN函数用于计算返回的结果集中某一列的最小值。
例如我们想知道高能物理科目的最低分是多少,则可以使用以下语句:

1
SELECT MIN(score) FROM scores_t WHERE subject = '高能物理';  

将返回:

MIN(score)
29
MAX

MAX函数用于计算返回的结果集中某一列的最大值。
例如我们想知道创意写作科目的最高分是多少,则可以使用以下语句:

1
SELECT MAX(score) FROM scores_t WHERE subject = '创意写作';  

将返回:

MAX(score)
100
DISTINCT

当我们想对返回的结果去重时,可以使用DISTINCT来修饰列名。
例如我们只想知道有哪些同学,则可以使用以下语句:

1
SELECT DISTINCT student_name FROM scores_t;  

将返回:

student_name
屈屈
慧心
达琳
COUNT

COUNT函数用于计算返回的结果集中有多少行数据。
例如当我们想知道有成绩表中一共有多少行记录,则可以使用以下语句:

1
SELECT COUNT(*) FROM scores_t;  

将返回:

COUNT(*)
12

同时,COUNT也能与其它函数一起使用,例如我们想知道有多少个不同的学生,则可以使用以下语句:

1
SELECT COUNT(DISTINCT student_name) FROM scores_t;  

将返回:

COUNT(DISTINCT student_name)
3

想知道不及格的成绩有多少个,则可以使用以下语句:

1
SELECT COUNT(*) FROM scores_t WHERE score < 60;  

将返回:

COUNT(*)
2
SUM

SUM函数用于计算返回的结果集中某一列的和。
例如我们想知道成绩表中时尚美学科目的总分,则可以使用以下语句:

1
SELECT SUM(score) FROM scores_t WHERE subject = '时尚美学';  
AVG

AVG函数用于计算返回的结果集中某一列的平均值。
例如我们想知道成绩表中电子竞技科目的平均分,则可以使用以下语句:

1
SELECT AVG(score) FROM scores_t WHERE subject = '电子竞技';  

列的重命名

在SELECT部分,我们可以使用AS关键字对返回的结果集中的列进行重命名。
例如我们想知道成绩表中学生的姓名和分数,则可以使用以下语句:

1
SELECT student_name AS 姓名, score AS 分数, subject AS 科目 FROM scores_t LIMIT 1;  

将返回:

姓名 分数 科目
屈屈 100 创意写作

同时,我们也可以使用AS关键字对函数的返回值进行重命名。
例如我们想知道成绩表中电子竞技科目的平均分,则可以使用以下语句:

1
SELECT AVG(score) AS 平均分 FROM scores_t WHERE subject = '电子竞技';  

另外AS关键字可以省略,例如以下语句与上面的等价:

1
SELECT AVG(score) 平均分 FROM scores_t WHERE subject = '电子竞技';  

WHERE

筛选数据

WHERE用于筛选数据,在WHERE字句部分,我们常使用以下运算符对筛选条件进行修饰:

1
2
= 、  >  、  <  、  >=  、  <=  、 !=  、
BETWEEN 、 IN 、 LIKE 、 IS NULL 、 IS NOT NULL

其中:

  • != 表示 不等于。
  • BETWEEN 表示在某个范围内,例如 score BETWEEN 60 AND 80,表示成绩在60到80之间,等价于 score >= 60 AND score <= 80。
  • IN 表示在某个集合内,例如 subject IN (‘电子竞技’, ‘创意写作’),表示科目是电子竞技或者创意写作。
  • LIKE 表示模糊匹配,例如 student_name LIKE ‘屈%’,表示学生名字以屈开头的;百分号的位置可以在任意位置,例如 student_name LIKE ‘%琳’,则表示学生名字以琳结尾的;百分号可以有多个。
  • IS NULL 表示为空,不常用。
  • IS NOT NULL 表示不为空,不常用。

例如我们想知道成绩表中电子竞技科目的不及格的同学,则可以使用以下语句:

1
2
SELECT * FROM scores_t 
WHERE subject = '电子竞技' AND score < 60;

将返回:

student_id student_name subject score
3 达琳 电子竞技 59

条件组合

不同的WHERE条件可以通过AND和OR关键字组合使用。
例如我们想知道成绩表中电子竞技和高能物理科目不及格或优分(>=80分)的成绩,则可以使用以下语句:

1
2
3
4
5
SELECT * FROM scores_t
WHERE
(subject = '电子竞技' OR subject = '高能物理')
AND
(score < 60 OR score >= 80);

与以下SQL等价:

1
2
3
4
5
SELECT * FROM scores_t 
WHERE
subject IN ('电子竞技', '高能物理')
AND
(score < 60 OR score >= 80);

PS:感受到不用BETWEEN的好处了吗,通过条件组合,我们可以更灵活地筛选数据。

拓展:AND优先级的优先级高于OR,例如A OR B AND C,等价于 A OR (B AND C)。
但是不用记,不要炫技,就记住使用括号来改变优先级即可。

GROUP BY

GROUP BY的作用是对数据进行分组,常与SELECT中的函数一起使用。除了在垂直学习章节中介绍的与SUM函数一起使用,还常与MIN、MAX、COUNT、AVG等函数一起使用。
例如我们想知道每个科目的平均分,则可以使用以下语句:

1
2
SELECT subject, AVG(score) FROM scores_t
GROUP BY subject;

将返回:

subject AVG(score)
创意写作 91.3333
时尚美学 75.6667
电子竞技 80.6667
高能物理 63.6667

SELECT字句中也可以与多个函数一起使用。例如我们不仅想知道每个科目的平均分,还想知道最高分和最低分,则可以使用以下语句:

1
2
SELECT subject, AVG(score), MIN(score), MAX(score) FROM scores_t
GROUP BY subject;

将返回:

subject AVG(score) MIN(score) MAX(score)
创意写作 91.3333 81 100
时尚美学 75.6667 62 100
电子竞技 80.6667 59 91
高能物理 63.6667 29 85

这样就能同时统计多个维度的数据了,一目了然。

除了对单个列进行分组,我们还可以对多个列进行分组。例如对于下面这张表,增加了班级列和部分同学的成绩。

student_id student_name class subject score
1 屈屈 1班 创意写作 100
1 屈屈 1班 时尚美学 100
1 屈屈 1班 电子竞技 92
1 屈屈 1班 高能物理 29
2 慧心 2班 创意写作 81
2 慧心 2班 时尚美学 62
2 慧心 2班 电子竞技 91
2 慧心 2班 高能物理 85
3 达琳 1班 创意写作 93
3 达琳 1班 时尚美学 65
3 达琳 1班 电子竞技 59
3 达琳 1班 高能物理 77
4 森贝 2班 创意写作 88
4 森贝 2班 时尚美学 75
4 森贝 2班 电子竞技 83
4 森贝 2班 高能物理 90

我们想按班级统计每个科目的平均分,则可以使用以下语句:

1
2
SELECT class, subject, AVG(score) FROM scores_t
GROUP BY class, subject;

将返回:

class subject AVG(score)
1班 创意写作 96.5000
1班 时尚美学 82.5000
1班 电子竞技 75.5000
1班 高能物理 53.0000
2班 创意写作 84.5000
2班 时尚美学 68.5000
2班 电子竞技 87.0000
2班 高能物理 87.5000

HAVING

HAVING的作用是对GROUP BY的结果进行筛选。例如我们想筛选平均分大于80的学生,则可以使用以下语句:

1
2
3
SELECT student_name, AVG(score) FROM scores_t
GROUP BY student_name
HAVING AVG(score) > 80;

将返回:

student_name AVG(score)
屈屈 80.2500
森贝 84.0000

注意这里前提是没有重名的学生,否则应该以学生ID作为分组依据。

如果我们想知道至少有一门科目成绩为满分的学生,则可以使用以下语句:

1
2
3
4
SELECT student_name
FROM scores_t
GROUP BY student_name
HAVING MAX(score) = 100;

将返回:

student_name
屈屈

在HAVING字句中,我们还可以进行更复杂的判断,例如我们想知道至少有哪些同学有两门及以上科目成绩相同,则可以使用以下语句:

1
2
3
4
SELECT student_name
FROM scores_t
GROUP BY student_id, student_name
HAVING COUNT(DISTINCT score) < COUNT(score);

将返回:屈屈,因为屈屈同学的创意写作和时尚美学都考了100分。

ORDER BY

ORDER BY的作用是对返回的结果集进行排序。排序分为升序和降序两种情况:

  • 升序,添加ASC关键字,默认情况下就是升序,所以也可以省略ASC关键字。
  • 降序,添加DESC关键字

Tips:建议无论何时都不要省略关键字,因为这样可以让SQL语义更清晰,并且如果去记忆默认的排序方式,不累吗。

例如我们想升序查看电子竞技成绩表中的数据,则可以使用以下语句:

1
2
3
SELECT * FROM scores_t
WHERE subject = '电子竞技'
ORDER BY score ASC;
student_id student_name class subject score
3 达琳 1班 电子竞技 59
4 森贝 2班 电子竞技 83
2 慧心 2班 电子竞技 91
1 屈屈 1班 电子竞技 92

ORDER BY也可以对多个列进行排序,例如我们想以降序方式查看所有成绩,但是又希望先查看1班的成绩,再查看2班的,即1班的成绩排在2班的前面。则可以使用以下语句:

1
2
SELECT * FROM scores_t
ORDER BY class ASC, score DESC;

返回数据:

student_id student_name class subject score
1 屈屈 1班 创意写作 100
1 屈屈 1班 时尚美学 100
3 达琳 1班 创意写作 93
1 屈屈 1班 电子竞技 92
3 达琳 1班 高能物理 77
3 达琳 1班 时尚美学 65
3 达琳 1班 电子竞技 59
1 屈屈 1班 高能物理 29
2 慧心 2班 电子竞技 91

LIMIT

LIMIT的作用是限制返回的结果集的行数。例如我们想知道成绩表中创意写作前三名的同学,则可以使用以下语句:

1
2
3
4
SELECT * FROM scores_t
WHERE subject = '创意写作'
ORDER BY score DESC
LIMIT 3;
student_id student_name class subject score
1 屈屈 1班 创意写作 100
3 达琳 1班 创意写作 93
4 森贝 2班 创意写作 88

LIMIT的另一个常见用法是分页,例如我们仅仅是想查看创意写作第3名的成绩,则可以使用以下语句:

1
2
3
4
SELECT * FROM scores_t
WHERE subject = '创意写作'
ORDER BY score DESC
LIMIT 1 OFFSET 2;

返回数据:

student_id student_name class subject score
4 森贝 2班 创意写作 88

其中OFFSET 2表示跳过前两行数据,即从第三行开始返回数据,LIMIT 1表示限制返回1行数据。

其中OFFSET关键词可以省略,例如以下语句与上面的等价:

1
2
3
4
SELECT * FROM scores_t
WHERE subject = '创意写作'
ORDER BY score DESC
LIMIT 2, 1;

此时LIMIT后面的第一个数字表示跳过的行数,第二个数字表示限制返回的行数。

分页用法在实际工作中很常见,例如在网页中展示数据时,一页展示不下所有数据,就需要分页展示,这时候就可以使用LIMIT来实现。例如每页10条数据,要展示第5页的数据,就可以使用LIMIT 40, 10来实现。

拓展:在分页时,如果跳过的行数很多,会带来显著的性能问题,导致查询速度变慢。这种现象我们称之为深分页,因为数据库需要扫描和丢弃大量无用的数据行。

点此访问在线练习平台,暂只支持电脑端访问
反馈建议请点此