MySQL 高阶查询语句:子查询、连接查询与多表关联

MySQL 高阶语句是数据库查询、数据处理的核心能力,主要包括子查询连接查询 (内连接、外连接)、多表关联查询等,以下结合文档核心内容+实用拓展,系统总结:

一、子查询(Subquery)

1. 核心定义(文档核心)

子查询是嵌套在其他 SQL 语句(SELECT/INSERT/UPDATE/DELETE)中的查询语句,其结果作为外层查询的「条件」「数据源」或「计算依据」,本质是"用一个查询辅助另一个查询"。

2. 核心作用

作为外层查询的过滤条件(如 WHERE 子句中);

作为外层查询的数据源(如 FROM 子句中,也称"派生表");

作为字段值(如 SELECT 子句中,需返回单行单列结果)。

3. 分类(面试高频)

按返回结果类型可分为 4 类,对应不同使用场景:

子查询类型 返回结果 常用关键字 适用场景
单行子查询 单个值(1 行 1 列) =、>、<、>=、<= 外层查询需单个条件匹配(如查询"工资高于部门平均工资的员工")
多行子查询 多个值(多行 1 列) IN、NOT IN、ANY、ALL 外层查询需匹配多个条件(如查询"属于销售部或技术部的员工")
多列子查询 多个字段(多行多列) IN(需字段数匹配) 外层查询需多字段联合匹配(如查询"与某员工部门+岗位都相同的人")
关联子查询 依赖外层查询的参数(逐行执行) EXISTS、NOT EXISTS 需判断"存在性"(如查询"有下属的部门"),效率常优于 IN 子查询

4. 实用示例

(1)单行子查询(=)
SQL 复制代码
-- 查询工资高于部门平均工资的员工(部门 ID=3)
SELECT name, salary 
FROM employees 
WHERE dept_id=3 AND salary > (
    SELECT AVG(salary) FROM employees WHERE dept_id=3
);
(2)多行子查询(IN)
SQL 复制代码
-- 查询"销售部"或"技术部"的员工(先查部门 ID,再匹配员工)
SELECT name, dept_id 
FROM employees 
WHERE dept_id IN (
    SELECT id FROM departments WHERE dept_name IN ('销售部', '技术部')
);
(3)关联子查询(EXISTS)
SQL 复制代码
-- 查询有下属的部门(依赖外层部门 ID,判断是否存在对应员工)
SELECT dept_name 
FROM departments d 
WHERE EXISTS (
    SELECT 1 FROM employees e WHERE e.dept_id = d.id
);

二、连接查询(JOIN)

连接查询用于关联多个表的数据,核心是通过「共同字段」(如主键-外键)建立关联,文档重点讲了内连接、左连接、右连接,以下补充全连接、自连接及优化要点。

1. 核心连接类型

连接类型 定义(核心逻辑) 语法 不匹配记录处理 适用场景
内连接(INNER JOIN) 只返回两表中「满足连接条件」的记录 SELECT ... FROM 表A INNER JOIN 表B ON 表A.字段=表B.字段; 全部过滤 需获取两表"交集"数据(如匹配员工和其部门信息)
左连接(LEFT JOIN) 以「左表」为基准,返回左表所有记录 + 右表匹配记录 SELECT ... FROM 表A LEFT JOIN 表B ON 表A.字段=表B.字段; 右表字段填充 NULL 需保留左表全部数据(如查询所有员工,即使未分配部门)
右连接(RIGHT JOIN) 以「右表」为基准,返回右表所有记录 + 左表匹配记录 SELECT ... FROM 表A RIGHT JOIN 表B ON 表A.字段=表B.字段; 左表字段填充 NULL 需保留右表全部数据(如查询所有部门,即使无员工)
全连接(FULL JOIN) 返回两表所有记录,匹配的合并,不匹配的填充 NULL MySQL 不直接支持,用:LEFT JOIN UNION RIGHT JOIN 两边不匹配字段均为 NULL 需获取两表"全集"数据(如合并两个表的所有记录)

2. 自连接(SELF JOIN)

自连接是「表与自身的连接」,需通过别名区分两个"虚拟表",常用于查询"具有层级关系"或"自身关联"的数据(如员工与上级、分类与子分类)。

示例:查询员工及其直接上级
SQL 复制代码
-- 员工表 employees(id, name, manager_id),manager_id 关联自身 id
SELECT e.name AS 员工姓名, m.name AS 上级姓名
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;

3. 连接查询的核心注意事项

「ON vs WHERE」:ON 是「连接条件」(筛选关联的记录),WHERE 是「最终过滤条件」(筛选已关联后的记录);

避免笛卡尔积:必须指定连接条件(ON 子句),否则两表会全量关联(如 1000 行 × 1000 行 = 100 万行,性能极差);

索引优化:连接字段(如主键、外键)建议创建索引,可大幅提升连接效率。

三、多表关联查询(3 张及以上表)

1. 实现方式

通过「连续使用 JOIN 子句」关联多张表,每个 JOIN 都需指定"关联表"和"连接条件",建议使用表别名(如 s 代表 students)简化 SQL。

2. 经典示例

假设有 3 张表:

students(id:学生 ID,name:学生姓名)

scores(id:成绩 ID,student_id:关联学生 ID,course_id:关联课程 ID,score:分数)

courses(id:课程 ID,course_name:课程名称)

需求:查询"所有学生的姓名、所选课程名称及对应分数"(含未选课的学生)

SQL 复制代码
SELECT 
  s.name AS 学生姓名,
  c.course_name AS 课程名称,
  sc.score AS 分数
FROM students s  -- 左表:学生表(保留所有学生)
LEFT JOIN scores sc ON s.id = sc.student_id  -- 关联成绩表(学生-成绩)
LEFT JOIN courses c ON sc.course_id = c.id;  -- 关联课程表(成绩-课程)

3. 多表连接拓展技巧

关联顺序:优先关联数据量小的表(如字典表、分类表),再关联大表(如订单表、用户表),提升查询效率;

字段歧义:多表中若有同名字段(如 id),必须通过「表别名.字段名」指定(如 <s.id>、<sc.id>),否则 SQL 报错;

过滤条件:多表连接时,过滤条件尽量写在对应表的 ON 子句中(如只查"数学"课程,可在 courses 关联时加 ON sc.course_id = c.id AND c.course_name='数学'),减少关联后的数据量。

四、高阶查询优化建议(面试高频补充)

  1. 子查询 vs 连接查询:简单子查询可直接使用,复杂子查询(如多层嵌套)建议改为连接查询(JOIN),因为 MySQL 对连接查询的优化更成熟,效率更高;

  2. 索引设计:子查询的条件字段、连接查询的关联字段,建议创建 B+ 树索引(如 student_id、course_id),避免全表扫描;

  3. 限制返回结果:使用 LIMIT 限制返回行数,避免大数据量查询拖慢数据库;

  4. 避免 SELECT *:只查询需要的字段,减少数据传输和内存占用。

总结

MySQL 高阶语句的核心是「灵活组合子查询与连接查询」,解决多表数据关联、复杂条件筛选的需求。

相关推荐
心态还需努力呀8 小时前
从 Oracle 到 KingbaseES:一次真实项目的数据库国产化迁移实录
数据库·oracle
枷锁—sha9 小时前
【PortSwigger Academy】SQLi UNION 攻击 (确定列数)
服务器·数据库·学习·安全·网络安全
qq_366086229 小时前
sql server多字段字符串模糊查询存在字段null值查询失效问题
数据库
无籽西瓜a9 小时前
详解Redis持久化:RDB、AOF与混合持久化
数据库·redis·缓存
人工智能知识库9 小时前
华为HCCDA-GaussDB题库(带详细解析)
数据库·华为·gaussdb·题库·hccda-gaussdb·hccda
齐 飞9 小时前
数据库批量插入耗时过长问题rewriteBatchedStatements=true
数据库·mysql
sg_knight9 小时前
SQL 中的 IFNULL 函数是什么?
数据库·sql·mysql·oracle·database·关系型数据库·db
程序员黄老师9 小时前
一分钟了解时序数据库(TSDB)
大数据·数据库·时序数据库
你才是臭弟弟9 小时前
时序数据库TDengine TSDB(安装/介绍)
数据库·时序数据库·tdengine
正在走向自律9 小时前
从“可用”到“好用”:金仓时序数据库开发者体验深度测评与二次开发生态搭建指南
数据库·时序数据库·金仓数据库