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

相关推荐
科技小花4 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸4 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain4 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希4 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神4 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员4 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java5 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿5 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴5 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存
YOU OU5 小时前
三大范式和E-R图
数据库