在 SQL 中使用 子查询(Subquery) 很容易踩坑,尤其是性能、语义和 NULL 处理方面。下面从常见坑点 → 规避方法 → 实战建议三个层面说明。
SELECT *
FROM orders o
WHERE o.amount > (
SELECT AVG(amount)
FROM orders o2
WHERE o2.customer_id = o.customer_id
);
❌ 问题:
✅ 解决:
JOIN + 聚合SELECT o.*
FROM orders o
JOIN (
SELECT customer_id, AVG(amount) avg_amt
FROM orders
GROUP BY customer_id
) t ON o.customer_id = t.customer_id
WHERE o.amount > t.avg_amt;
SELECT *
FROM users
WHERE id NOT IN (
SELECT user_id FROM orders
);
❌ 如果 orders.user_id 有 NULL:
NOT IN 结果可能为空✅ 解决方式:
NOT EXISTSSELECT *
FROM users u
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);
✅ 或排除 NULL
WHERE id NOT IN (
SELECT user_id FROM orders WHERE user_id IS NOT NULL
);
SELECT * FROM a
WHERE (x, y) IN (SELECT x FROM b); -- ❌ 错误
✅ 正确:
WHERE (x, y) IN (SELECT x, y FROM b);
SELECT *
FROM users
WHERE id IN (SELECT user_id FROM orders);
✅ 没问题,但 JOIN 可能重复:
SELECT u.*
FROM users u
JOIN orders o ON u.id = o.user_id;
❌ 一个用户多订单 → 结果重复
✅ 解决:
SELECT DISTINCT u.*
或先去重子查询
SELECT ...
FROM (
SELECT ...
FROM (
SELECT ...
)
)
❌ 难维护、难优化
✅ 解决:
WITH t1 AS (...),
t2 AS (...)
SELECT * FROM t2;
| 场景 | 建议 |
|---|---|
| 子查询被外层反复执行 | ❌ 改 JOIN |
| 大表 + 子查询 | ❌ 避免 |
| 只需要判断存在 | ✅ EXISTS |
| 简单过滤 | ✅ IN |
| 多层嵌套 | ✅ CTE |
✅ 能用 JOIN 就别用子查询
✅ 能用 EXISTS 就别用 NOT IN
✅ 子查询里先过滤、先聚合
✅ 注意 NULL(尤其是 NOT IN)
✅ 复杂逻辑优先 CTE
子查询不是不能用,而是:小数据可用、存在判断用 EXISTS、性能敏感用 JOIN、NULL 一定要小心。
如果你有具体 SQL 或数据库(MySQL / PostgreSQL / Oracle),我可以直接帮你改写优化。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。