子查询入门|标量 / 行 / 列子查询,简化复杂查询

子查询入门|标量 / 行 / 列子查询,简化复杂查询

前言

我们已经学会用多表 JOIN 完成复杂业务查询,但在很多场景下,先查一个值 / 一列 / 一行,再用它做条件会更简单直观,这就是子查询。子查询是 SQL 从 “会用” 到 “熟练” 的关键台阶,也是面试与日常开发高频用法。

本篇从定义、分类、语法、场景、案例、避坑完整精讲,带你一次性掌握标量子查询、列子查询、行子查询三大基础类型,代码可直接复制运行


一、本章知识点汇总

  1. 子查询定义与执行逻辑
  2. 子查询三大基础类型:标量、列、行
  3. 标量子查询:返回单行单列,用= > < >= <=
  4. 列子查询:返回单列多行,用IN / ANY / ALL
  5. 行子查询:返回单行多列,用复合条件匹配
  6. 子查询书写位置:SELECT / WHERE / FROM
  7. 三大子查询实战案例(用户 - 订单 - 商品场景)
  8. 子查询与 JOIN 简单对比
  9. 高频注意事项与职场规范
  10. 课后练习题 + 思路

二、各知识点详解

1. 什么是子查询?

子查询(嵌套查询):在一个 SQL 内部嵌套另一个 SELECT 查询,先执行内层查询,把结果交给外层查询使用。

  • 外层查询:主查询
  • 内层查询:子查询
  • 子查询必须用( )包裹
  • 执行顺序:先子查询,后主查询

2. 三大基础子查询(按返回结果分类)

表格

类型返回结果可用操作符常用位置难度
标量子查询单行单列(一个值)= > < >= <= <>WHERE / SELECT★☆☆
列子查询单列多行(一列值)IN / ANY / ALLWHERE★★☆
行子查询单行多列(一组值)多字段组合匹配WHERE★★★

3. 标量子查询(最常用、最简单)

核心定义

返回一行一列(一个值:数字、字符串、日期)。

适用场景

  • 查单个值做条件:高于平均分、最新时间、最大 ID
  • SELECT 里动态加计算列

语法

sql

SELECT 字段 FROM 表 WHERE 字段 = (标量子查询);

4. 列子查询(条件范围查询)

核心定义

返回一列多行(一列表数据),相当于一个值列表

适用场景

  • 查询在某个集合内的数据:所有有订单的用户、买过某类商品的人
  • 替代多表连接简化逻辑

常用关键字

  • IN:在列表中任意一个
  • ANY:满足任意一个
  • ALL:满足所有

5. 行子查询(多字段组合匹配)

核心定义

返回一行多列,用于同时匹配多个字段的场景。

适用场景

  • 同时匹配:部门 + 职位、分类 + 价格、用户 + 状态
  • 简化多条件并列写法

语法

sql

WHERE (字段1,字段2) = (行子查询)

三、实战环境准备(直接复制运行)

沿用前面电商表结构,确保连贯学习:

sql

-- 用户表 CREATE TABLE users ( user_id INT PRIMARY KEY, user_name VARCHAR(20) NOT NULL ); -- 订单表 CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, amount DECIMAL(10,2), order_time DATE ); -- 商品表 CREATE TABLE goods ( goods_id INT PRIMARY KEY, goods_name VARCHAR(30), price DECIMAL(10,2) ); INSERT INTO users VALUES (1,'张三'),(2,'李四'),(3,'王五'),(4,'赵六'); INSERT INTO orders VALUES (1001,1,299,'2024-06-01'), (1002,2,420,'2024-06-02'), (1003,3,88,'2024-06-03'); INSERT INTO goods VALUES (1,'笔记本',299),(2,'键盘',159),(3,'T恤',99);

四、应用案例及结果分析

案例 1:标量子查询实战(高频)

需求 1:查询订单金额高于平均金额的订单

sql

SELECT * FROM orders WHERE amount > (SELECT AVG(amount) FROM orders);
  • 子查询先算:平均订单金额
  • 外层筛选:大于平均值的订单
  • 典型报表筛选用法

需求 2:SELECT 中使用标量子查询(动态列)

查询所有订单,并显示订单总金额(全局总计):

sql

SELECT order_id, user_id, amount, (SELECT SUM(amount) FROM orders) AS total_amount FROM orders;

案例 2:列子查询实战(范围匹配)

需求:查询下过订单的所有用户信息

sql

SELECT * FROM users WHERE user_id IN (SELECT DISTINCT user_id FROM orders);
  • 子查询返回:所有有订单的 user_id 列表
  • 外层 IN 匹配:只保留有订单的用户
  • 等价于内连接,但更简洁

案例 3:行子查询实战(组合匹配)

需求:查询与订单 1001同用户、同金额的订单

sql

SELECT * FROM orders WHERE (user_id, amount) = ( SELECT user_id, amount FROM orders WHERE order_id=1001 );
  • 一次性匹配两个字段
  • 比写user_id=xx AND amount=xx更简洁

五、注意事项

  1. 标量子查询必须只返回 1 个值返回多行 → 报错:子查询返回多于 1 行
  2. 列子查询只能返回 1 列多列会直接语法错误
  3. 行子查询字段数量、类型必须一一对应
  4. 子查询尽量简单,不要嵌套过深(可读性差)
  5. 能用子查询简化就不用复杂 JOIN,但超大表优先 JOIN
  6. 不要在子查询里用 ORDER BY(无意义、影响性能)
  7. 条件优先放WHERE,少用 HAVING + 子查询

六、核心总结

  1. 子查询 = 查询嵌套查询,先内后外执行
  2. 三大基础类型:
    • 标量:单行单列 → 用= > <
    • :单列多行 → 用IN / ANY / ALL
    • :单行多列 → 组合匹配
  3. 标量子查询最常用:平均值、最大值、动态列
  4. 列子查询适合:范围筛选、存在性判断
  5. 行子查询适合:多字段同时匹配
  6. 子查询让复杂逻辑分步拆解,更易读、易维护

一句话记忆:标量返回一个值,列是列表用 IN;行是组合多字段,子查询先内后外真省心


七、课后实战练习题(附思路)

题目 1

标量子查询:查询价格高于所有商品平均价的商品名称、价格。

题目 2

列子查询:查询没有下过订单的用户(NOT IN)。

题目 3

行子查询:查询和 “张三” 同一个用户、且金额相同的所有订单。


参考答案思路

题目 1:

sql

SELECT goods_name, price FROM goods WHERE price > (SELECT AVG(price) FROM goods);

题目 2:

sql

SELECT * FROM users WHERE user_id NOT IN (SELECT DISTINCT user_id FROM orders);

题目 3:

sql

SELECT * FROM orders WHERE (user_id, amount) = ( SELECT user_id, amount FROM orders WHERE user_id = (SELECT user_id FROM users WHERE user_name='张三') );