SQL 连接查询用法总结

SQL 连接查询用法总结

核心:多表通过关联字段拼接数据,分为内连接、左连接、右连接、全连接、交叉连接

一、基础语法通用格式

sql 复制代码
SELECT 字段
FROM 表1
连接类型 JOIN 表2
ON 表1.关联字段 = 表2.关联字段;

二、五类连接详解

1. 内连接 INNER JOIN

只返回两表匹配成功的数据,交集部分

sql 复制代码
SELECT *
FROM user u
INNER JOIN order o
ON u.id = o.user_id;

简写:可省略INNER,直接写JOIN

2. 左连接 LEFT JOIN

以左表为基准,左表数据全部保留,右表匹配不上显示null

sql 复制代码
-- 查询所有用户及对应订单,无订单也保留用户
SELECT *
FROM user u
LEFT JOIN order o
ON u.id = o.user_id;

3. 右连接 RIGHT JOIN

以右表为基准,右表数据全部保留,左表匹配不上显示null

sql 复制代码
SELECT *
FROM user u
RIGHT JOIN order o
ON u.id = o.user_id;

4. 全连接 FULL JOIN

取两表所有数据,匹配不上字段补空

sql 复制代码
SELECT *
FROM user u
FULL JOIN order o
ON u.id = o.user_id;

注:MySQL不原生支持,可用左右连接合并实现

5. 交叉连接 CROSS JOIN

笛卡尔积,两表行数相乘组合,极少主动使用

sql 复制代码
SELECT * FROM user CROSS JOIN goods;

三、关键区分速记

连接类型 数据范围 使用场景
INNER JOIN 两边匹配数据 只查有关联的有效数据
LEFT JOIN 左表全部+匹配右表 主表数据必展示,附属信息可选
RIGHT JOIN 右表全部+匹配左表 极少用,可互换表改用左连接
FULL JOIN 两表全部数据 汇总全部台账数据

四、常用拓展写法

  1. 多表连续连接
sql 复制代码
SELECT *
FROM user u
LEFT JOIN order o ON u.id=o.user_id
LEFT JOIN pay p ON o.id=p.order_id;
  1. 连接后加筛选条件
  • ON:连接前过滤关联规则
  • WHERE:连接结果后整体筛选
sql 复制代码
SELECT *
FROM user u
LEFT JOIN order o ON u.id=o.user_id
WHERE o.create_time>'2025-01-01';

五、实操要点

  1. 关联字段一般为主键、外键,保证对应关系
  2. 字段重名需加表别名区分
  3. 优先左连接,可读性更高,日常业务最常用
  4. 内连接自动过滤无效无关联数据

六、例题

学生表: Students

Column Name Type
student_id int
student_name varchar

在 SQL 中,主键为 student_id(学生ID)。

该表内的每一行都记录有学校一名学生的信息。

科目表: Subjects

Column Name Type
subject_name varchar
在 SQL 中,主键为 subject_name(科目名称)。
每一行记录学校的一门科目名称。

考试表: Examinations

Column Name Type
student_id int
subject_name varchar

这个表可能包含重复数据(换句话说,在 SQL 中,这个表没有主键)。

学生表里的一个学生修读科目表里的每一门科目。

这张考试表的每一行记录就表示学生表里的某个学生参加了一次科目表里某门科目的测试。

查询出每个学生参加每一门科目测试的次数,结果按 student_id 和 subject_name 排序。

查询结构格式如下所示。

示例 1:

输入:

Students table:

student_id student_name
1 Alice
2 Bob
13 John
6 Alex

Subjects table:

subject_name
Math
Physics
Programming

Examinations table:

student_id subject_name
1 Math
1 Physics
1 Programming
2 Programming
1 Physics
1 Math
13 Math
13 Programming
13 Physics
2 Math
1 Math

输出:

student_id student_name subject_name attended_exams
1 Alice Math 3
1 Alice Physics 2
1 Alice Programming 1
2 Bob Math 1
2 Bob Physics 0
2 Bob Programming 1
6 Alex Math 0
6 Alex Physics 0
6 Alex Programming 0
13 John Math 1
13 John Physics 1
13 John Programming 1

解释:

结果表需包含所有学生和所有科目(即便测试次数为0):

Alice 参加了 3 次数学测试, 2 次物理测试,以及 1 次编程测试;

Bob 参加了 1 次数学测试, 1 次编程测试,没有参加物理测试;

Alex 啥测试都没参加;

John 参加了数学、物理、编程测试各 1 次。

题目分析 + 左外连接完整解法

这道题是经典的多表左连接 + 分组统计 考题,核心难点在于:
必须让每个学生 × 每门科目都出现一行,哪怕一次考试都没参加


解题思路

  1. 生成「所有学生 × 所有科目」的完整组合
  • 学生表(所有学生)
  • 科目表(所有科目)
  • 用 笛卡尔积(CROSS JOIN) 生成:每个学生对应每一门科目
    → 这是保证「不漏学生、不漏科目」的关键
  1. 左连接考试表,统计参加次数
  • 用 LEFT JOIN 把考试表关联上去
  • 没参加考试的次数记为 0
  1. 分组 + 排序
  • 按 student_id, subject_name 分组统计次数
  • 最后按要求排序

最终 SQL 代码

sql 复制代码
SELECT
  s.student_id,
  s.student_name,
  sub.subject_name,
  COUNT(e.student_id) AS attended_exams  -- 统计考试次数
FROM
  Students s
CROSS JOIN
  Subjects sub  -- 生成 每个学生 × 每门科目
LEFT JOIN
  Examinations e  -- 左连接考试表(不丢组合)
  ON s.student_id = e.student_id
  AND sub.subject_name = e.subject_name
GROUP BY
  s.student_id, s.student_name, sub.subject_name
ORDER BY
  s.student_id, sub.subject_name;

关键步骤解释

  1. CROSS JOIN 作用
    Students CROSS JOIN Subjects

    直接生成:所有学生 × 所有科目 的完整组合

    哪怕学生没考过某科目,这一行依然存在

  2. LEFT JOIN 为什么必须这么写

sql 复制代码
LEFT JOIN Examinations e
  ON s.student_id = e.student_id
  AND sub.subject_name = e.subject_name
  • 以「学生+科目」为主表
  • 左边完整保留
  • 右边匹配不到考试记录 → 显示 NULL
  • COUNT(e.student_id) 会自动把 NULL 记为 0
  1. 统计次数
    COUNT(e.student_id)
  • 参加过 → 计数 +1
  • 没参加 → 计 0

为什么不能直接用考试表?

因为考试表里缺少没参加考试的学生/科目组合

直接统计会漏数据,必须先生成完整组合,再左连接考试表。

相关推荐
编程火箭车2 小时前
MySQL 拥抱 AI:向量、RAG、AutoML 全进了数据库
数据库·mysql·ai编程·向量数据库·rag·automl·mysql9
用户8662978480083 小时前
KingbaseES 中文乱码、排序不对?区域和字符集的问题,一次说清
数据库
aruo3 小时前
回退旧镜像之前,先确认数据库还能兼容
数据库
张洛闻Eren3 小时前
Ansible【第三课】:管理变量和事实
数据库·oracle
weixin_382395234 小时前
0-500 人工厂的生产 PMC 系统怎么做?基于 Tauri + SQLite 的性能架构实践与 5000 物料压测实录
数据库·架构·sqlite
l1t4 小时前
DeepSeek总结的 DuckDB 2.0 文档新内容
服务器·网络·数据库
IvorySQL5 小时前
PostgreSQL 日报| PG19 主备切换挂起修复(10 月 17 日)
数据库·postgresql
roman_日积跬步-终至千里5 小时前
【数据Agent论文·查询与语义|11】EntSQL:给了业务文档,模型为何还是写不对SQL?
数据库·人工智能·sql·数据分析
2601_962885725 小时前
如何用 Python 算最大回撤和回撤恢复期?
java·数据库·python
zcn1265 小时前
Left join+or exists+like关联优化
数据库·sql优化改写