SQL-查询

【SQL 教程】基础查询入门:从表数据查询到连接测试全解析

一、SELECT语句基础用法

2.1 查询表中所有数据

语法格式

sql 复制代码
SELECT * FROM <表名>;
  • SELECT:关键字,标识查询操作
  • *:通配符,表示查询所有列
  • FROM:指定数据来源表

示例演示

sql 复制代码
-- 查询学生表所有数据
SELECT * FROM students;

-- 查询班级表所有数据
SELECT * FROM classes;

执行结果

返回包含列名和数据的二维表结构,例如classes表查询结果:

csv 复制代码
id,name
1,一班
2,二班
3,三班
4,四班

2.2 不带FROM子句的特殊用法

场景 1:表达式计算
sql 复制代码
-- 直接计算数值表达式
SELECT 100 + 200;

结果

复制代码
100 + 200
300
场景 2:数据库连接测试

核心用途 :检测工具通过执行SELECT 1;验证数据库连接有效性

sql 复制代码
-- 经典连接测试语句
SELECT 1;

原理:无需操作具体表,仅验证数据库服务响应能力

三、关键概念总结

知识点 说明
查询本质 SELECT语句返回的结果是一个二维表,包含列定义和行数据
通配符* 代表表中所有列,生产环境建议明确指定列名以提升性能
无表查询 利用SELECT直接计算或测试连接,是 SQL 灵活性的体现

四、开发建议

  1. 避免滥用SELECT * :明确列出所需列可减少数据传输量,提升查询效率
  2. 连接测试最佳实践 :使用轻量语句SELECT 1而非复杂查询,降低资源消耗
  3. 养成注释习惯 :如示例中通过--添加注释,增强 SQL 可读性

SQL 进阶之路:WHERE 条件查询全解析,轻松筛选有效数据

前言

在关系型数据库中,精准筛选数据是高频需求。

一、基础语法:从全表到精准筛选

核心作用

通过WHERE子句过滤出符合条件的记录,避免返回全表数据,提升查询效率。

语法结构

sql 复制代码
SELECT 字段列表 FROM 表名 WHERE 条件表达式;

示例:查询高分学生

需求:获取分数≥80 分的学生记录

sql 复制代码
SELECT * FROM students WHERE score >= 80;

执行结果

csv 复制代码
id,class_id,name,gender,score
1,1,小明,M,90
2,1,小红,F,95
3,1,小军,M,88
...

二、逻辑运算符:组合条件的核心

1. AND(逻辑与)

作用 :同时满足多个条件
示例:查询分数≥80 分的男生

sql 复制代码
SELECT * FROM students 
WHERE score >= 80 AND gender = 'M';

2. OR(逻辑或)

作用 :满足任意一个条件
示例:查询分数≥80 分或性别为男的学生

sql 复制代码
SELECT * FROM students 
WHERE score >= 80 OR gender = 'M';

3. NOT(逻辑非)

作用 :排除符合条件的记录
示例 :查询非 2 班的学生(等价于class_id <> 2

sql 复制代码
SELECT * FROM students 
WHERE NOT class_id = 2;

三、条件表达式:丰富的筛选维度

条件类型 表达式示例 说明
等值判断 score = 80 字符串需用单引号(如name = '小明'
范围判断 score > 90 支持><>=<=
不等值判断 score <> 60 等价于!=
模糊查询 name LIKE '小%' %匹配任意字符,_匹配单个字符(如'_明'匹配 "小明""A 明")
区间查询 score BETWEEN 60 AND 90 闭区间,等价于score >=60 AND score <=90
枚举查询 class_id IN (1, 3) 匹配列表中的任意值,等价于多个OR组合

四、优先级与括号:避免逻辑歧义

运算符优先级(从高到低)

  1. NOT
  2. AND
  3. OR

括号改变优先级

示例:查询分数 <80 或> 90 的男生

sql 复制代码
-- 正确写法(先算括号内逻辑)
SELECT * FROM students 
WHERE (score < 80 OR score > 90) AND gender = 'M';

-- 错误写法(实际等价于 score <80 OR (score>90 AND gender='M'))
SELECT * FROM students 
WHERE score < 80 OR score > 90 AND gender = 'M';

五、实战演练:经典场景解析

场景 1:查询 60-90 分之间的学生

正确写法

sql 复制代码
-- 方式1:AND组合
SELECT * FROM students 
WHERE score >= 60 AND score <= 90;

-- 方式2:BETWEEN(更简洁)
SELECT * FROM students 
WHERE score BETWEEN 60 AND 90;

场景 2:查询姓名含 "小" 的女生

sql 复制代码
SELECT * FROM students 
WHERE name LIKE '%小%' AND gender = 'F';

六、注意事项

  1. 字符串单引号 :文本值必须用单引号包裹(如gender = 'M'),数值型无需引号
  2. NULL 值处理 :判断空值用IS NULL(如comment IS NULL),不能用=
  3. 性能优化 :对查询条件字段添加索引(如scorename),提升大数据量查询速度

【SQL 教程】投影查询:精准筛选列数据的核心技巧

一、什么是投影查询?

定义 :通过SELECT语句指定需要查询的列,而非返回表的所有列(SELECT *),这种操作称为投影查询。
核心作用

  • 减少返回数据量,提升查询效率;
  • 聚焦业务所需字段,简化结果集结构。

基础语法

sql 复制代码
SELECT 列1, 列2, 列3 FROM 表名;

示例 :从students表中查询idscorename三列:

sql 复制代码
SELECT id, score, name FROM students;

二、给列起别名:优化结果可读性

通过别名(Alias)可以自定义结果集的列名,语法如下:

sql 复制代码
SELECT 列名 别名, 列名 AS 别名 FROM 表名;

说明

  • AS关键字可选,省略时直接写别名(如score points);
  • 别名建议见名知意,方便后续处理(如报表展示)。

示例 :将score列重命名为points

sql 复制代码
SELECT id, score AS points, name FROM students;

三、投影查询 + WHERE 条件:精准过滤数据

投影查询可与WHERE子句结合,实现 "列筛选 + 行过滤" 的双重条件查询。
语法

sql 复制代码
SELECT 列1, 列2 FROM 表名 WHERE 条件;

示例 :查询男生的idscore(别名points)和name

sql 复制代码
SELECT id, score points, name FROM students WHERE gender = 'M';

结果集

csv 复制代码
id,points,name
1,90,小明
3,88,小军
...

四、实战注意事项(来自评论区经验)

  1. AS 关键字是否必须?

    • 标准 SQL 中AS可选,但显式使用更易读(如score AS points),推荐保留。
  2. 中文别名如何处理?

    • 部分数据库(如 MySQL)支持中文别名,需用反引号`````包裹:

      sql 复制代码
      SELECT id `编号`, name `姓名` FROM students;
    • 若出现乱码,需检查表 / 字段的字符集设置(如 UTF-8)。

  3. 别名能否用于 WHERE 子句?

    • 不能 。别名是SELECT阶段生成的结果集标识,WHERE执行时别名尚未生效。
    • 若需过滤别名数据,需用原列名或嵌套子查询。

五、小结

核心知识点 说明
投影查询 SELECT 列1, 列2替代SELECT *,仅返回指定列
列别名 AS或直接指定别名,优化结果集列名可读性
条件组合 结合WHERE子句,实现列与行的双重筛选
最佳实践 显式使用AS增强可读性,中文别名用反引号包裹,避免在WHERE中使用别名

SQL 进阶之路:如何用 ORDER BY 让查询结果 "井然有序"?

在 SQL 查询中,原始结果集的顺序往往由数据库引擎决定(通常按主键排序),但实际开发中我们经常需要自定义排序规则 。本文将结合实例,详解ORDER BY子句的核心用法,让你的查询结果 "按需排列"。

一、基础排序:按单列升序排列

核心语法

sql 复制代码
SELECT 列1, 列2,...
FROM 表名
ORDER BY 排序列; -- 默认为升序(ASC)

实战案例

查询学生表,按成绩从低到高排序:

sql 复制代码
SELECT id, name, gender, score 
FROM students 
ORDER BY score;
执行结果(部分):
id name gender score
6 小兵 M 55
4 小米 F 73
5 小白 F 81
... ... ... ...

二、倒序排列:用 DESC 实现降序

核心语法

sql 复制代码
SELECT 列1, 列2,...
FROM 表名
ORDER BY 排序列 DESC; -- DESC表示倒序

实战案例

按成绩从高到低排序:

sql 复制代码
SELECT id, name, gender, score 
FROM students 
ORDER BY score DESC;
执行结果(部分):
id name gender score
2 小红 F 95
8 小新 F 91
1 小明 M 90
... ... ... ...

三、多列排序:复杂场景下的精准控制

当排序列存在重复值时,可通过多列排序进一步细化规则。

核心语法

sql 复制代码
SELECT 列1, 列2,...
FROM 表名
ORDER BY 排序列1 [ASC/DESC], 排序列2 [ASC/DESC],...;

实战案例

先按成绩降序,若成绩相同则按性别升序(F 在前,M 在后):

sql 复制代码
SELECT id, name, gender, score 
FROM students 
ORDER BY score DESC, gender;
执行结果(部分):
id name gender score
2 小红 F 95 -- 成绩最高,性别 F 优先
8 小新 F 91 -- 同成绩下 F 在前
1 小明 M 90 -- 同成绩下 M 在后
... ... ... ...

四、关键细节:默认规则与执行顺序

  1. 默认排序规则

    • 未指定ASC/DESC时,默认使用ASC(升序)。
    • 例:ORDER BY score 等价于 ORDER BY score ASC
  2. 与 WHERE 子句的配合

    • 执行顺序:先过滤(WHERE),再排序(ORDER BY)。

    • 案例:查询一班学生,按成绩降序排列:

      sql 复制代码
      SELECT id, name, gender, score 
      FROM students 
      WHERE class_id = 1  -- 先过滤班级
      ORDER BY score DESC; -- 再排序

五、最佳实践建议

  1. 索引优化

    • 对排序列添加索引(如score),可显著提升排序性能。
    • 多列排序时,索引顺序应与ORDER BY列顺序一致(如(score DESC, gender))。
  2. 避免 SELECT

    • 仅查询必要字段,减少排序数据量,提升效率。
  3. 谨慎使用表达式排序

    • 若需按计算结果排序(如ORDER BY price * quantity),建议先通过AS命名别名:

      sql 复制代码
      SELECT id, price, quantity, price*quantity AS total
      FROM orders
      ORDER BY total DESC;

SQL 分页查询全解析:LIMIT/OFFSET 用法与性能优化指南

一、引言:为什么需要分页查询?

在数据量较大的场景下(如数万条记录),一次性返回所有数据会导致:

  • 前端渲染性能下降
  • 网络传输效率低下
  • 用户体验差

分页查询通过 "结果集切片" 技术,实现数据的分批展示,典型应用场景包括:

  • 网站列表分页(如商品列表、文章列表)
  • API 接口数据分页(如分页加载更多)
  • 大数据量报表的分段展示

二、核心语法:LIMIT/OFFSET 的使用

2.1 基础语法结构

sql 复制代码
SELECT column1, column2,...
FROM table_name
[WHERE condition]
ORDER BY column [ASC/DESC]
LIMIT offset, limit;
-- 或
LIMIT limit OFFSET offset;
  • LIMIT:指定返回记录的最大数量(必选)
  • OFFSET:指定查询结果的起始偏移量(可选,默认 0)

2.2 分页查询示例(每页 3 条记录)

表数据排序(按成绩降序):

sql 复制代码
SELECT id, name, gender, score 
FROM students 
ORDER BY score DESC;

第 1 页(偏移 0,取前 3 条)

sql 复制代码
SELECT ... LIMIT 3 OFFSET 0;
-- 或简写:LIMIT 0, 3;

执行结果

csv 复制代码
id,name,gender,score
2,小红,F,95
8,小新,F,91
1,小明,M,90

第 2 页(偏移 3,取第 4-6 条)

sql 复制代码
SELECT ... LIMIT 3 OFFSET 3;
-- 简写:LIMIT 3, 3;

执行结果

csv 复制代码
id,name,gender,score
9,小王,M,89
3,小军,M,88
10,小丽,F,88

2.3 分页参数计算公式

设:

  • pageSize:每页显示记录数(如 3)

  • pageIndex:当前页码(从 1 开始)

则:

  • LIMIT = pageSize

  • OFFSET = (pageIndex - 1) * pageSize

示例:第 4 页参数计算

sql 复制代码
pageSize = 3, pageIndex = 4
OFFSET = (4-1)*3 = 9
-- 查询语句:LIMIT 3 OFFSET 9;

三、关键注意事项

3.1 OFFSET 的可选性

  • OFFSET=0时可省略,直接写LIMIT 10(等价于LIMIT 10 OFFSET 0

3.2 MySQL 的简写语法

sql 复制代码
LIMIT offset, limit; -- 等价于 LIMIT limit OFFSET offset;

注意:第一个参数是偏移量,第二个是数量

3.3 大偏移量的性能问题

  • OFFSET值较大时(如OFFSET 100000),数据库需先扫描前 100000 条记录再丢弃,导致性能下降
  • 优化建议:避免深度分页(如超过 1000 页),或采用索引优化(见下文)

四、性能优化技巧

4.1 基于索引的分页优化

场景:当数据按自增主键(如 id)排序时,可利用索引快速定位起始点

优化方法

  1. 第一页查询:
sql 复制代码
SELECT * FROM students 
WHERE id >= 0 
ORDER BY id ASC 
LIMIT 101; -- 多取1条判断是否有下一页
  1. 下一页查询(用上一页最后一条 id 作为起始点):
sql 复制代码
SELECT * FROM students 
WHERE id >= last_id 
ORDER BY id ASC 
LIMIT 101;
  • 若返回记录数 = 101:存在下一页,取前 100 条,记录最后一条 id
  • 若返回记录数 < 101:最后一页

优势 :避免使用大OFFSET,直接通过索引定位起始行

4.2 避免 SELECT *

  • 只查询需要的字段,减少数据传输量
sql 复制代码
-- 优化前
SELECT * FROM students ...

-- 优化后
SELECT id, name, score FROM students ...

五、总页数计算方法

5.1 精确计算法(适用于需要显示总页数的场景)

  1. 获取总记录数
sql 复制代码
SELECT COUNT(*) AS total_records FROM students;
  1. 计算总页数(使用 CEIL 函数向上取整):
sql 复制代码
SET @page_size = 10;
SELECT CEIL(total_records / @page_size) AS total_pages;

示例:总记录数 123,每页 10 条 → 总页数 13

5.2 注意事项

  • 避免使用 COUNT (id) :若存在主键缺失(如删除记录),会导致结果不准确
  • 推荐使用 COUNT (*) : 统计所有行,性能更优

5.3 非精确计算法(适用于无限滚动场景)

  • 不计算总页数,通过前端 "加载更多" 按钮动态获取下一页
  • 后台逻辑:每次查询多取 1 条,判断是否还有更多数据

六、常见问题与讨论

6.1 主键不连续问题

  • 自增主键可能存在断号(如删除记录后),因此不能通过主键最大值计算总记录数
  • 廖雪峰建议:自增主键仅用于唯一标识,绝不参与业务逻辑

6.2 同分数排序的重复问题

  • 当排序字段存在相同值时(如并列分数),需添加辅助排序字段(如 id)保证唯一性
sql 复制代码
ORDER BY score DESC, id ASC;

一文搞懂 SQL 聚合查询:从基础函数到分组统计实战

引言

在 SQL 查询中,统计数据是日常开发中高频需求。

一、什么是聚合查询?

聚合查询 是通过 SQL 内置的聚合函数,对表中数据进行统计计算的查询方式。
核心作用

  • 快速统计数据总量、平均值、最值等
  • 结合分组功能,实现多维度数据分析
    与普通查询的区别
    普通查询返回每行具体数据,而聚合查询返回统计后的单行或分组统计结果

二、常用聚合函数详解

函数 作用 示例场景
COUNT() 统计行数 统计学生总数:COUNT(*)
SUM() 计算某列数值总和 计算总分:SUM(score)
AVG() 计算某列数值平均值 计算平均分:AVG(score)
MAX() 获取某列最大值(支持数值 / 字符类型) 最高成绩:MAX(score)
MIN() 获取某列最小值(支持数值 / 字符类型) 最低年龄:MIN(age)

2.1 COUNT() 函数深度解析

1. COUNT(*) vs COUNT(列名)
  • COUNT(*) :统计所有行(包括NULL值)

    sql 复制代码
    SELECT COUNT(*) FROM students; -- 返回总记录数
  • COUNT(列名) :统计该列非NULL的行数

    sql 复制代码
    SELECT COUNT(name) FROM students; -- 统计有姓名的学生数
2. 结合WHERE条件过滤统计
sql 复制代码
-- 统计男生人数
SELECT COUNT(*) boys FROM students WHERE gender = 'M';

2.2 数值型聚合函数(SUM/AVG)

sql 复制代码
-- 计算男生平均成绩
SELECT AVG(score) average FROM students WHERE gender = 'M';

-- 计算班级总分
SELECT SUM(score) total FROM students WHERE class_id = 1;

2.3 最值函数(MAX/MIN)

sql 复制代码
-- 获取最高成绩
SELECT MAX(score) highest_score FROM students;

-- 获取最晚注册时间(字符类型按排序规则处理)
SELECT MAX(register_time) FROM users;

三、分组查询:GROUP BY 的使用

3.1 单字段分组

需求:统计每个班级的学生人数

sql 复制代码
SELECT class_id, COUNT(*) num 
FROM students 
GROUP BY class_id;

结果解读

class_id num
1 4
2 3
3 3

3.2 多字段分组

需求:统计每个班级男女生人数

sql 复制代码
SELECT class_id, gender, COUNT(*) num 
FROM students 
GROUP BY class_id, gender;

结果解读

class_id gender num
1 M 2
1 F 2
2 M 2
... ... ...

3.3 分组查询注意事项

  1. SELECT 子句限制

    • 非聚合列必须出现在GROUP BY中(MySQL 默认宽松模式除外,需注意ONLY_FULL_GROUP_BY模式)
    sql 复制代码
    -- 错误示例(name未分组)
    SELECT name, class_id, COUNT(*) FROM students GROUP BY class_id;
  2. 分组顺序影响结果

    多字段分组时,按分组字段顺序层级分组(先按class_id,再按gender)。

四、实战练习

练习 1:查询每个班级的平均分

sql 复制代码
SELECT class_id, AVG(score) average_score 
FROM students 
GROUP BY class_id;

预期结果

class_id average_score
1 86.5
2 73.67
3 89.33

练习 2:查询每个班级男女生的平均分

sql 复制代码
SELECT class_id, gender, AVG(score) average_score 
FROM students 
GROUP BY class_id, gender;

预期结果

class_id gender average_score
1 M 89.0
1 F 84.0
2 M 70.0
... ... ...

五、高级技巧:聚合函数的特殊行为

5.1 空值处理

  • COUNT(*):返回 0(无匹配行时)
  • SUM/AVG/MAX/MIN:返回NULL(无匹配行时)
sql 复制代码
-- 无女生的班级,AVG返回NULL
SELECT AVG(score) FROM students WHERE gender = 'X';

5.2 性能优化建议

  • 避免在COUNT()中使用不必要的列(COUNT(*)效率更高)
  • 对分组字段添加索引(提升GROUP BY性能)

六、常见问题与解决方案

6.1 MySQL 中分组查询非聚合列报错

现象

sql 复制代码
ERROR 1055: Expression #1 is not in GROUP BY clause...

原因 :MySQL 启用了ONLY_FULL_GROUP_BY模式(严格模式)。
解决方案

  1. 将非聚合列加入GROUP BY

  2. 使用聚合函数包裹(如MAX(name)

  3. 临时关闭严格模式(不推荐生产环境):

    sql 复制代码
    SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES';

七、总结

核心知识点回顾:

  1. 聚合函数COUNT/SUM/AVG/MAX/MIN的用法与场景
  2. 分组查询GROUP BY单字段 / 多字段分组逻辑
  3. 数据过滤 :结合WHERE条件实现精准统计
  4. 数据库差异:MySQL 与标准 SQL 在分组查询中的行为差异

SQL 多表查询深度解析:从笛卡尔积到实战优化

在关系型数据库的查询操作中,多表查询是整合多维度数据的核心技能。

一、笛卡尔积查询:多表查询的基础形态

1. 笛卡尔积的本质

当使用 SELECT * FROM table1, table2 语法执行多表查询时,数据库会返回两张表的笛卡尔积 结果:即 table1 每一行与 table2 每一行的全组合。结果集的行数为两表行数的乘积,列数为两表列数之和。

示例代码

sql 复制代码
-- 无过滤条件的笛卡尔积查询
SELECT * FROM students, classes;

结果特征(以示例数据为例):

  • 学生表(10 行)× 班级表(4 行)= 40 行结果
  • 列名冲突问题:两表均包含idname列,结果集出现重复列名

2. 列别名与表别名的使用

为解决列名冲突问题,可通过投影查询为列设置别名,或为表设置别名简化引用:

(1)列别名优化
sql 复制代码
SELECT
  students.id AS sid,    -- 学生表ID别名
  students.name,
  classes.id AS cid,     -- 班级表ID别名
  classes.name AS cname
FROM students, classes;
(2)表别名简化
sql 复制代码
SELECT
  s.id sid,
  s.name,
  c.id cid,
  c.name cname
FROM students s, classes c;  -- 表别名语法:FROM 表名 别名

二、条件过滤:缩小笛卡尔积结果集

通过 WHERE 子句添加过滤条件,可大幅减少笛卡尔积的无效数据。例如,查询男生(gender='M')所在的 1 班(classes.id=1)数据:

sql 复制代码
SELECT
  s.id sid,
  s.name,
  c.id cid,
  c.name cname
FROM students s, classes c
WHERE s.gender = 'M' AND c.id = 1;

执行逻辑

  1. 先生成两表的笛卡尔积(40 行)
  2. 应用 WHERE 条件过滤,仅保留同时满足 gender='M'classes.id=1 的行(5 行)

三、笛卡尔积的局限性与实战陷阱

1. 性能风险:数据爆炸问题

  • 当两表数据量较大时(如各 1 万行),笛卡尔积将生成1 亿行数据,严重消耗数据库资源
  • 典型场景:未加关联条件的多表查询、误将逗号分隔的多表语法当作连接查询使用

2. 业务逻辑错误

笛卡尔积默认不关联表间业务关系(如学生与班级的所属关系)。若未通过外键关联(如 students.class_id = classes.id),结果将包含大量无意义的组合(如学生属于不存在的班级)。

四、正确姿势:基于外键的关联查询

实际开发中,多表查询需通过主键 - 外键关系 建立有效关联。以学生 - 班级场景为例,正确做法是通过 class_id 外键关联两表:

sql 复制代码
SELECT
  s.name 学生姓名,
  c.name 班级名称,
  s.score 成绩
FROM students s, classes c
WHERE s.class_id = c.id;  -- 关键:通过外键建立关联

对比笛卡尔积

  • 结果集仅包含实际存在的学生 - 班级组合(如示例中 10 行,而非 40 行)
  • 避免无效数据,提升查询效率

五、开发者常见问题与社区讨论

问题 1:笛卡尔积的实际应用场景?

  • 极少直接使用,但可用于:

    • 理解连表查询底层逻辑(如自连接场景)
    • 生成测试数据或枚举组合(需严格控制数据量)

问题 2:如何避免列名冲突?

  • 强制使用 表名.列名 或别名,如 s.id 而非直接写 id
  • 工具层面:使用 SQL 客户端(如 Navicat)的字段别名提示功能

一文搞懂 SQL 连接查询:从内连接到外连接的全面解析

引言

在 SQL 查询中,多表关联是处理复杂业务场景的核心能力。本文将通过实际案例和图示,详细解析内连接(INNER JOIN)左外连接(LEFT OUTER JOIN) 、** 右外连接(RIGHT OUTER JOIN)全外连接(FULL OUTER JOIN)** 的原理与用法,帮助你快速掌握多表数据关联的核心逻辑。

一、为什么需要连接查询?

假设我们有两张表:

  • students表(学生信息):包含idnameclass_id(班级 ID)等字段

  • classes表(班级信息):包含idname(班级名称)等字段

需求 :查询学生信息时,需要同时显示对应的班级名称。

此时,仅凭单表查询无法获取classes表中的班级名称,必须通过连接查询 将两张表的数据按关联字段(class_idid)拼接起来。

二、内连接(INNER JOIN)

核心逻辑

  • 仅返回两张表中满足连接条件的行(交集部分)。

  • 语法:

    sql 复制代码
    SELECT 字段列表
    FROM 主表 AS 别名
    INNER JOIN 关联表 AS 别名
    ON 连接条件; -- 例如:主表.外键 = 关联表.主键

示例

查询所有学生及其班级名称(仅显示存在对应班级的学生):

sql 复制代码
SELECT 
  s.id, s.name, s.class_id, 
  c.name AS class_name,  -- 别名简化字段名
  s.gender, s.score
FROM students AS s
INNER JOIN classes AS c
ON s.class_id = c.id;

结果

id name class_id class_name gender score
1 小明 1 一班 M 90
2 小红 1 一班 F 95
... ... ... ... ... ...

三、外连接(OUTER JOIN)

外连接会保留某张表的全部数据,缺失的关联数据用NULL填充,分为三种类型:

1. 左外连接(LEFT OUTER JOIN)

核心逻辑
  • 保留左表的全部行 ,右表中无匹配的行用NULL填充。

  • 语法:

    sql 复制代码
    SELECT ...
    FROM 左表 AS s
    LEFT OUTER JOIN 右表 AS c
    ON s.class_id = c.id;
示例

假设新增一名班级 ID 为 5 的学生(classes表中无班级 ID=5 的记录):

sql 复制代码
INSERT INTO students (class_id, name, gender, score) 
VALUES (5, '新生', 'M', 88);

查询结果:

sql 复制代码
SELECT s.id, s.name, s.class_id, c.name AS class_name
FROM students AS s
LEFT OUTER JOIN classes AS c
ON s.class_id = c.id;

结果

id name class_id class_name gender score
... ... ... ... ... ...
11 新生 5 NULL M 88 -- 左表独有数据,右表字段为 NULL

2. 右外连接(RIGHT OUTER JOIN)

核心逻辑
  • 保留右表的全部行 ,左表中无匹配的行用NULL填充。

  • 语法:

    sql 复制代码
    SELECT ...
    FROM 左表 AS s
    RIGHT OUTER JOIN 右表 AS c
    ON s.class_id = c.id;
示例

查询所有班级及其学生(包括没有学生的班级 "四班"):

sql 复制代码
SELECT s.id, s.name, s.class_id, c.name AS class_name
FROM students AS s
RIGHT OUTER JOIN classes AS c
ON s.class_id = c.id;

结果

id name class_id class_name gender score
... ... ... ... ... ...
NULL NULL NULL 四班 NULL NULL -- 右表独有数据,左表字段为 NULL

3. 全外连接(FULL OUTER JOIN)

核心逻辑
  • 保留两张表的全部行 ,无匹配的行用NULL填充(等价于左外连接 + 右外连接的并集)。

  • 注意 :MySQL 不直接支持FULL OUTER JOIN,可通过UNION组合左右外连接结果实现。

    sql 复制代码
    SELECT ... FROM A LEFT JOIN B ON ...
    UNION
    SELECT ... FROM A RIGHT JOIN B ON ...;
示例(假设数据库支持):
sql 复制代码
SELECT s.id, s.name, s.class_id, c.name AS class_name
FROM students AS s
FULL OUTER JOIN classes AS c
ON s.class_id = c.id;

结果

包含左表独有行(班级 ID=5 的学生)和右表独有行(四班),缺失字段为NULL

四、连接类型对比图

用维恩图直观表示不同连接的结果集范围:

plaintext 复制代码
+-----------------+        +-----------------+
|      tableA     |        |      tableB     |
+--------+--------+        +--------+--------+
| id=1   | name=A |        | id=1   | name=X |
| id=2   | name=B |        | id=2   | name=Y |
| id=3   | name=C |        | id=4   | name=Z |
+-----------------+        +-----------------+

- INNER JOIN:仅返回A和B中id相同的行(id=1, 2)
- LEFT JOIN:返回A的全部行(id=1,2,3),B中无匹配的行用NULL填充
- RIGHT JOIN:返回B的全部行(id=1,2,4),A中无匹配的行用NULL填充
- FULL JOIN:返回A和B的全部行(id=1,2,3,4),缺失数据用NULL填充

五、实战技巧

  1. 别名优化
    用短别名(如s代表studentsc代表classes)简化语句,提高可读性。
  2. 连接条件
    始终使用ON子句指定连接条件(如主表.外键 = 关联表.主键),避免使用WHERE子句导致性能问题。
  3. 优先使用内连接
    除非需要保留某张表的全部数据,否则优先用内连接,避免返回冗余的NULL行。

六、小结

连接类型 核心作用 数据保留策略
INNER JOIN 查询两张表的交集数据 仅保留匹配行
LEFT JOIN 保留左表全部数据,补全右表关联数据 左表全保留,右表匹配或 NULL
RIGHT JOIN 保留右表全部数据,补全左表关联数据 右表全保留,左表匹配或 NULL
FULL JOIN 保留两张表全部数据
相关推荐
Access开发易登软件5 分钟前
Access开发导出PDF的N种姿势,你get了吗?
后端·低代码·pdf·excel·vba·access·access开发
悟乙己11 分钟前
数据科学家如何更好地展示自己的能力
大数据·数据库·数据科学家
叫我阿柒啊24 分钟前
从Java全栈到前端框架:一位程序员的实战之路
java·spring boot·微服务·消息队列·vue3·前端开发·后端开发
皆过客,揽星河30 分钟前
mysql进阶语法(视图)
数据库·sql·mysql·mysql基础语法·mysql进阶语法·视图创建修改删除
mqiqe44 分钟前
架构-亿级流量性能调优实践
java·架构
中国胖子风清扬1 小时前
Rust 序列化技术全解析:从基础到实战
开发语言·c++·spring boot·vscode·后端·中间件·rust
bobz9651 小时前
分析 docker.service 和 docker.socket 这两个服务各自的作用
后端
tuokuac1 小时前
Redis 的相关文件作用
数据库·redis·缓存
野犬寒鸦1 小时前
力扣hot100:旋转图像(48)(详细图解以及核心思路剖析)
java·数据结构·后端·算法·leetcode
七夜zippoe2 小时前
AI+Java 守护你的钱袋子!金融领域的智能风控与极速交易
java·人工智能·金融