如何在mysql中使用子查询_mysql子查询基础讲解

子查询是在SQL语句中嵌套的SELECT查询,可用于WHERE、FROM、SELECT列表和HAVING子句;标量子查询必须返回0或1行1列,否则需改用IN或EXISTS。

MySQL 中的子查询,就是在一个 SQL 语句内部嵌套另一个 SELECT 查询。它让复杂逻辑可以分步表达,比如“查出销售额高于平均值的员工”,不用先算平均值再手动填数,一条语句就能搞定。

子查询能用在哪些位置

子查询最常出现在这几个地方:

  • WHERE 子句中:用于条件判断,比如 WHERE salary > (SELECT AVG(salary) FROM emp)
  • FROM 子句中:作为临时表(又叫派生表),例如 SELECT * FROM (SELECT id, name FROM user WHERE status=1) AS active_users
  • SELECT 列表中:返回单个值,常用于补充字段,如 SELECT name, (SELECT COUNT(*) FROM order WHERE user_id=u.id) AS order_count FROM user u
  • HAVING 子句中:配合分组使用,比如统计部门平均薪资高于公司平均的部门

必须注意的三个限制

子查询不是哪里都能随便写的,几个关键约束要记牢:

  • 标量子查询(用在 WHERE 或 SELECT 中)必须返回 0 或 1 行、1 列,否则会报错。如果不确定行数,可用 INEXISTS
  • WHERE 中用 =、>、;想查多个值,改用 IN (SELECT ...)
  • FROM 中的子查询必须起别名,否则 MySQL 会报语法错误,例如 FROM (SELECT ...) tt 就是必需的别名

IN、EXISTS 和 JOIN 的选择建议

当需要“查 A 表中在 B 表存在的记录”这类需求时,有三种写法,适用场景不同:

  • IN + 子查询:适合 B 表结果集小、且字段有索引,例如 SELECT * FROM user WHERE id IN (SELECT user_id FROM log WHERE type='login')
  • EXISTS:适合 B 表大、且关联条件能走索引,因为它是对外表每行做半连接判断,找到一个就停,效率通常更高
  • JOIN:如果还要取 B 表的字段,或者需要去重/聚合,直接 JOIN 更清晰、也更容易优化

提高可读性和性能的小技巧

子查询写多了容易绕晕,也容易慢。几个实用提醒:

  • 给子查询起有意义的别名,比如 (SELECT MAX(create_time) FROM audit_log WHERE target_id=u.id) AS last_audit
  • 避免在 WHERE 中写相关子查询(即引用外部表字段)且没加索引,可能造*表扫描
  • EXPLAIN 看执行计划,确认子查询是否被转成高效联接,特别是 MySQL 5.6+ 支持子查询物化和半连接优化
  • 逻辑特别复杂的,不妨拆成临时表或 CTE(MySQL 8.0+ 支持),比多层嵌套更易维护