CodeGym /课程 /SQL SELF /多个 JOIN 在一个查询里

多个 JOIN 在一个查询里

SQL SELF
第 12 级 , 课程 1
可用

想象一下,你数据库里的每张表其实就是一个大拼图的一块。学生表知道谁在上学,课程表知道学啥内容,报名表知道谁报了啥。但这些碎片单独看都没啥用。想看全图?那就得把它们拼起来——这时候就轮到多个 JOIN出场了。

现实里,数据经常被拆成相关的表,这样结构更清晰,也能避免重复。比如我们这个大学数据库,有这些表:

  • students — 学生信息。
  • enrollments — 学生选课信息。
  • courses — 课程信息。

如果你想查出所有学生、他们的课程和老师,就得用 JOIN 把三张表连起来。

JOIN 的执行顺序

用多个 JOIN 时,PostgreSQL 是从左到右处理的。也就是说,先连前两张表,然后再把结果和第三张表连起来,依次类推。

举个例子:

SELECT *
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id;
  1. 先把 studentsenrollmentsstudents.id = enrollments.student_id 连起来。
  2. 第一步的结果再和 coursesenrollments.course_id = courses.id 连起来。

顺序很重要,特别是表很大的时候。写错 JOIN 的结构,性能可能会掉得很惨。

例子:学生、课程和老师的列表

假设我们有这些表的数据:

students 表:

id name
1 Otto Song
2 Maria Chi
3 Alex Lin

courses 表:

id name teacher
101 Mathematics Ellen Moore
102 Physics James Okoro
103 Computer Science Nina Delgado

enrollments 表:

student_id course_id
1 101
1 103
2 102
3 101

查询:

SELECT
    students.name AS student_name,
    courses.name AS course_name,
    courses.teacher AS teacher_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id;

结果:

student_name course_name teacher_name
Otto Song Mathematics Ellen Moore
Otto Song Computer Science Nina Delgado
Maria Chi Physics James Okoro
Alex Lin Mathematics Ellen Moore

JOIN 查询里的过滤

你可以在 JOIN 查询里加过滤条件,限制返回的数据量,还能让查询更快。比如,只查学“Mathematics”课程的学生:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
WHERE courses.name = 'Mathematics';

结果:

student_name course_name
Otto Song Mathematics
Alex Lin Mathematics

JOIN 查询的优化

表很大的时候,优化查询就特别重要了。给你几个建议:

  1. 用索引

索引能让 PostgreSQL 查得更快,尤其是按主键连表的时候。记得在 enrollments 表的 student_idcourse_id 字段上建索引。

建索引的例子:

CREATE INDEX idx_enrollments_student_id ON enrollments(student_id);
CREATE INDEX idx_enrollments_course_id ON enrollments(course_id);

索引的细节你后面会学到,但这里先提一下,因为 JOIN 经常和索引一起用。

  1. 尽早过滤数据

WHERE 条件,能在 JOIN 前就把不需要的行过滤掉。比如:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
WHERE 
    courses.teacher = '伊万 彼得罗夫';
  1. 尽量减少要连的行数

别一上来就全表 JOIN,可以先用子查询把数据筛一遍:

SELECT
    students.name AS student_name,
    courses.name AS course_name
FROM 
    (SELECT * FROM students WHERE id IN (1, 2)) sub_students
INNER JOIN enrollments ON sub_students.id = enrollments.student_id
INNER JOIN courses ON enrollments.course_id = courses.id;

子查询(嵌套 SELECT)你马上就会学到,敬请期待 :P

复杂 JOIN 例子:学生、课程和学院

假设我们又加了一张 faculties 表:

faculties 表:

id name
10 工程学院
20 自然科学学院

courses 表更新:

id name teacher faculty_id
101 Mathematics Ellen Moore 10
102 Physics James Okoro 20
103 Computer Science Nina Delgado 10

想查学生、课程和学院,就再加一个 JOIN

SELECT
    students.name AS student_name,
    courses.name AS course_name,
    faculties.name AS faculty_name
FROM students
    INNER JOIN enrollments ON students.id = enrollments.student_id
    INNER JOIN courses ON enrollments.course_id = courses.id
    INNER JOIN faculties ON courses.faculty_id = faculties.id;

结果:

student_name course_name faculty_name
Otto Song Mathematics 工程学院
Otto Song Computer Science 工程学院
Maria Chi Physics 自然科学学院
Alex Lin Mathematics 工程学院

JOIN 的 SQL 查询虽然有点复杂,但能让你写出很强大的报表,挖出有用的信息。只要结构和优化搞对了,它们就是你玩转大数据库的利器!

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