SQL SELECT查询语句详解
在数据库操作中,数据查询是数据库的核心操作。只要你和数据库打交道,百分之八十的时间都在写查询语句。而在 SQL 语言中,提供数据查询功能的就是大名鼎鼎的 SELECT 语句。
SELECT 语句不仅使用方式灵活,而且功能极其丰富。今天,我们将通过一个具体的“学生-课程”数据库,手把手教你彻底掌握 SELECT 的各大核心子句!
1. 准备具体数据表
为了让大家能清晰地看到每条 SELECT 语句执行后的效果,我们先准备三张基础表:学生表(Student)、课程表(Course)和选课成绩表(Sc)。
表1:Student(学生表)
| Sno (学号) | Sname (姓名) | Age (年龄) | Dept (所在系) |
|---|---|---|---|
| 03090101 | 张功杰 | 19 | 信息系统 |
| 05090102 | 吴肇星 | 19 | 计算机 |
| 05090106 | 王娴 | 18 | 计算机 |
表2:Course(课程表)
| Cno (课程号) | Cname (课程名) | Credit (学分) |
|---|---|---|
| 140001 | 数据库原理 | 3 |
| 140501 | 计算机网络 | 3 |
| 110501 | 会计学 | 2 |
表3:Sc(选课成绩表)
| Sno (学号) | Cno (课程号) | Grade (成绩) |
|---|---|---|
| 03090101 | 140001 | 80 |
| 03090101 | 140501 | 85 |
| 03090101 | 110501 | 75 |
| 05090102 | 140001 | 90 |
| 05090102 | 140501 | 95 |
2. 基础查询:SELECT 与 FROM
SELECT 语句最基本的结构就是告诉数据库:“我要从哪张表(FROM),查哪些列(SELECT)”。
2.1 查询指定列与全部列
如果你只对部分属性列感兴趣,可以在 SELECT 后跟上具体的列名。
SELECT Sname, Age FROM Student;
如果想查询所有列,可以简单地使用 * 通配符代表全部列。
2.2 消除重复的行 (DISTINCT)
有时查询的结果中会有重复值(例如查询学校里都有哪些系)。如果使用了 DISTINCT 关键词,系统就会在结果中去掉重复的行。
SELECT DISTINCT Dept FROM Student;
结果集将只返回“信息系统”和“计算机”两行,如果没有 DISTINCT,缺省默认是保留重复行的(ALL)。
3. 条件过滤:WHERE 子句
我们通常不需要表里的所有数据,此时可以通过 WHERE 子句来查询满足指定条件的元组。WHERE 支持丰富的查询条件:
- 比较大小:
=, >, <, >=, <=, !=, <>等。 - 确定范围:
BETWEEN ... AND ...或NOT BETWEEN。 - 确定集合:
IN或NOT IN,用来查找属性值属于指定集合的元组。 - 字符匹配 (LIKE):这是非常强大的模糊查询工具。
%代表任意长度的字符串,_代表任意单个字符。如果遇到字符串本身包含%或_的情况,还需要使用ESCAPE短语来进行转义。 - 空值查询:对于未录入或不知道的值,使用
IS NULL或IS NOT NULL来查询,注意不能使用=代替IS。 - 多重条件:用逻辑运算符
AND、OR或NOT将多个条件连接起来。
实战查询: 找出“计算机”系且年龄大于 18 岁的同学。
SELECT Sname, Age
FROM Student
WHERE Dept = '计算机' AND Age > 18;
(对照数据表,将精准返回“吴肇星, 19”这一条记录)
4. 数据统计:聚集函数 (Aggregate Functions)
为了增强检索功能,SQL 提供了许多方便的聚集函数:
COUNT(*):统计元组(行)的总个数。SUM(<列名>)/AVG(<列名>):计算一列值的总和 / 平均值(仅限数值型)。MAX(<列名>)/MIN(<列名>):求一列值中的最大值 / 最小值。
特别注意: 除了 COUNT(*) 之外,其他的聚集函数在计算时都会跳过空值(NULL)只处理非空值。而且,WHERE 子句中是不能使用聚集函数作为条件表达式的。
5. 分组与筛选:GROUP BY 与 HAVING
当我们想按某个维度进行统计(例如“求每个学生的平均成绩”)时,就需要用到 GROUP BY。
GROUP BY 子句将查询结果按某一列或多列的值分组,值相等的会被分入同一组。对查询结果分组的目的是为了细化聚集函数的作用对象;分组后,聚集函数将作用于每一个组,即每一组都有一个对应的函数计算值。
如果分组后还需要按一定条件对这些组进行筛选,就可以使用 HAVING 短语。
实战查询: 查询平均成绩大于 80 分的学生学号及其平均成绩。
SELECT Sno, AVG(Grade) AS 平均分
FROM Sc
GROUP BY Sno
HAVING AVG(Grade) > 80;
(结合聚集函数,系统会先按 Sno 将成绩表分为几组,然后分别计算每组的 AVG,最后利用 HAVING 剔除掉不满足 >80 条件的组)。
区别提示: WHERE 作用于基本表或视图,从中选择满足条件的元组;而 HAVING 作用于组,用于从中选择满足条件的组。
6. 结果排序:ORDER BY 子句
最后,为了让展示的数据更有条理,我们可以使用 ORDER BY 子句对查询结果按照一个或多个属性列进行排序。
- ASC(升序):从小到大排列(默认值)。
- DESC(降序):从大到小排列。
实战查询: 查询选修了课程“140501”的学生学号和成绩,并按成绩从高到低排序。
SELECT Sno, Grade
FROM Sc
WHERE Cno = '140501'
ORDER BY Grade DESC;
(根据 Sc 表,吴肇星(05090102)的 95 分会排在第一位,张功杰(03090101)的 85 分排在第二位)
总结
一个完整且复杂的单表 SELECT 查询通常遵循如下的标准语序骨架:
SELECT <目标列>
FROM <表名>
WHERE <行筛选条件>
GROUP BY <分组依据列>
HAVING <组筛选条件>
ORDER BY <排序依据列> ASC|DESC;