CodeGym /课程 /SQL SELF /FROM 里用子查询

FROM 里用子查询

SQL SELF
第 14 级 , 课程 1
可用

咱们再往 SQL 的兔子洞里钻一钻:聊聊怎么在 FROM 结构里用子查询。这是 SQL 开发者最常用的套路之一,因为你可以直接“现场”造出很强的临时表,还能像数据库里真有这表一样反复用。

比如你要写个报表,需要算点东西、分组、过滤数据,但又不想在服务器上建一堆临时表。咋办?这时候 FROM 里的子查询就能救你。它们可以:

  • 临时把数据合并或聚合一下,给主查询用。
  • “现场”造结构化的数据集。
  • 减少操作次数,让数据库不用存太多中间数据。

FROM 里的子查询就像迷你表,你可以在主查询里随便用。就像搭乐高一样:快、灵活,还不浪费资源 :)

FROM 里子查询的基础

FROM 里的子查询,就是用子查询造个临时表(或子表),让它变成整个查询的一部分。你只要做三步:

  1. FROM 结构里写个括号包起来的子查询。
  2. 给子查询起个别名(alias)。
  3. 像用普通表一样用这个别名。

语法

SELECT 列
FROM (
    SELECT 列
    FROM 表
    WHERE 条件
) AS 别名
WHERE 外部_条件;

是不是有点吓人?咱们直接看例子吧。

例子:学生和平均分

假设我们有两张表:

students(学生信息——名字和 ID):

student_id student_name
1 Alex
2 Anna
3 Dan

grades(学生成绩):

grade_id student_id grade
1 1 80
2 1 85
3 2 90
4 3 70
5 3 75

现在任务是:查出每个学生和他们的平均分。

我们可以先写个子查询算出每个学生的平均分,再在主查询里用它。

SELECT s.student_name, g.avg_grade
FROM (
    SELECT student_id, AVG(grade) AS avg_grade
    FROM grades
    GROUP BY student_id
) AS g
JOIN students AS s ON s.student_id = g.student_id;

结果:

student_name avg_grade
Alex 82.5
Anna 90.0
Dan 72.5

“现场”临时表

当你需要多层数据处理时,FROM 里的子查询特别有用。比如你不只想查平均分,还想查每个学生的最高分——全都在一个查询里搞定。

SELECT g.student_id, g.avg_grade, g.max_grade
FROM (
    SELECT student_id, 
           AVG(grade) AS avg_grade, 
           MAX(grade) AS max_grade
    FROM grades
    GROUP BY student_id
) AS g;

结果:

student_id avg_grade max_grade
1 82.5 85
2 90 90
3 72.5 75

注意,这就像一个完整的临时表,有自己的列:avg_grademax_grade

什么时候用 FROM 里的子查询最合适?

聚合数据时。 如果你想先算一波(比如平均、总和、最大值),再和别的表合并。

过滤数据时。 需要在和主表合并前先过滤一遍数据。

简化复杂查询时。 把复杂任务拆成几步,避免写得太乱。

例子:两层处理的学生报表

假如我们想找出平均分大于 80 的学生。先用子查询算平均分,再在外层过滤。

SELECT s.student_name, g.avg_grade
FROM students AS s
JOIN (
    SELECT student_id, AVG(grade) AS avg_grade
    FROM grades
    GROUP BY student_id
) AS g ON s.student_id = g.student_id
WHERE g.avg_grade > 80;

结果:

student_name avg_grade
Alex 82.5
Anna 90.0

使用小贴士和建议

别名必不可少。 子查询一定要起 alias(比如 AS g),不然 PostgreSQL 不知道怎么用这个“临时表”。

优化。 FROM 里的子查询有时候比表 JOIN 慢,尤其是你在子查询里过滤数据时。

索引。 用来关联的字段、索引和过滤条件要优化好——对性能影响很大。

复杂查询例子:课程和学生数量

来点难度的。假设我们有这样一张表:

courses(课程列表):

course_id course_name
1 SQL Basics
2 Python Basics

还有 enrollments(学生选课记录):

student_id course_id
1 1
1 2
2 1

现在我们想知道每门课有多少学生报名。

SELECT c.course_name, e.students_count
FROM courses AS c
JOIN (
    SELECT course_id, COUNT(student_id) AS students_count
    FROM enrollments
    GROUP BY course_id
) AS e ON c.course_id = e.course_id;

结果:

course_name students_count
SQL Basics 2
Python Basics 1

希望你喜欢这节讲座...下一节更有意思 :)

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION