EXISTS 是 SQL 中的一个子查询条件,用于检查子查询是否返回任何行。如果子查询返回至少一行,则 EXISTS 返回 TRUE。
例如,查询有订单的客户列表:
SELECT * FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
执行过程:
- 读取 customers 表的第一行,获取 c.id
- 执行子查询,检查 orders 表中是否有匹配的 customer_id
- 如果子查询返回任何行,则保留这个 customer
- 继续读取 customers 表的下一行,重复步骤2-3
- 直到处理完所有的 customers 记录
下面举几个实用的例子:
基本用法 - 查找有订单的客户:
SELECT * FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
NOT EXISTS - 查找没有订单的客户:
SELECT * FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
多表关联 - 查找有销售额超过1000的销售人员:
SELECT * FROM sales_staff s
WHERE EXISTS (SELECT 1 FROM orders o JOIN order_details od ON o.order_id = od.order_idWHERE o.sales_person_id = s.id GROUP BY o.sales_person_idHAVING SUM(od.amount) > 1000
);
条件组合 - 查找2023年有订单且订单状态为完成的客户:
SELECT * FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.idAND YEAR(o.order_date) = 2023AND o.status = 'completed'
);
更新语句中使用 - 更新有未付款订单的客户状态:
UPDATE customers c
SET status = 'pending_payment'
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.idAND o.payment_status = 'unpaid'
);
删除语句中使用 - 删除没有任何订单的客户:
DELETE FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
一些关键点:
- EXISTS 子查询通常使用 SELECT 1 或 SELECT *,因为 EXISTS 只关心是否返回行,不关心返回什么值
- EXISTS 的性能通常比 IN 好,特别是在大数据量时
- EXISTS 子查询中通常需要与外部表关联
- 可以和 NOT 结合使用来查找不存在的情况
使用建议:
- 当需要检查是否存在满足某个条件的记录时,优先考虑使用 EXISTS
- 在大数据量的情况下,EXISTS 通常比 IN 或 JOIN 有更好的性能
- 子查询中尽量只返回需要的字段,不要使用 SELECT *