You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化筛选双日期有订单且无中间订单的SQL查询?

更简洁高效的客户订单筛选方案

先回顾下你的场景:
我们有一个orders表,结构和测试数据如下:

CREATE TABLE orders (id SERIAL PRIMARY KEY, customer_id INT, created_at DATE) ;
INSERT INTO orders (customer_id, created_at) VALUES 
(1, '2019-10-09'), (1, '2019-10-01'), (1, '2019-08-09'), 
(2, '2019-10-09'), (2, '2019-10-09'), 
(3, '2019-09-09'), (3, '2019-08-09'), 
(4, '2019-08-09'), (4, '2019-08-09'), 
(5, '2019-10-09'), (5, '2019-10-09'), (5, '2019-08-09') ;

需求是:筛选出在2019-08-09和2019-10-09各至少有1笔订单,且这两个日期之间(2019-08-10到2019-10-08)没有任何订单的客户,示例中只有customer_id=5符合条件。

你已经用多个EXISTS子句实现了需求,写法如下:

SELECT DISTINCT(customer_id) 
FROM orders o1 
WHERE EXISTS (SELECT 1 FROM orders o2 WHERE o1.customer_id = o2.customer_id AND o2.created_at = '2019-10-09') 
  AND EXISTS (SELECT 1 FROM orders o2 WHERE o1.customer_id = o2.customer_id AND o2.created_at = '2019-08-09') 
  AND NOT EXISTS (SELECT 1 FROM orders o2 WHERE o1.customer_id = o2.customer_id AND o2.created_at BETWEEN '2019-08-10' AND '2019-10-08')

这个写法逻辑清晰,容易理解,但确实可以优化得更简洁高效——推荐用分组聚合+条件判断的方式,只需要扫描一次表就能完成筛选,性能更优:

方案一:使用BOOL_OR聚合函数(PostgreSQL专属)

PostgreSQL提供了BOOL_OR函数,只要分组内有任意一行满足条件就返回true,写法非常简洁:

SELECT customer_id
FROM orders
GROUP BY customer_id
HAVING BOOL_OR(created_at = '2019-08-09')
   AND BOOL_OR(created_at = '2019-10-09')
   AND NOT BOOL_OR(created_at BETWEEN '2019-08-10' AND '2019-10-08');

方案二:通用SQL写法(适配多数数据库)

如果需要兼容其他数据库,可以用COUNT条件聚合来实现:

SELECT customer_id
FROM orders
GROUP BY customer_id
HAVING COUNT(CASE WHEN created_at = '2019-08-09' THEN 1 END) >= 1
   AND COUNT(CASE WHEN created_at = '2019-10-09' THEN 1 END) >= 1
   AND COUNT(CASE WHEN created_at BETWEEN '2019-08-10' AND '2019-10-08' THEN 1 END) = 0;

为什么这两个方案更高效?

你的原写法用了三次EXISTS子查询,虽然PostgreSQL的查询优化器可能会做一些优化,但本质上是多次关联扫描表;而分组聚合的方式只需要对orders表进行一次全表扫描(如果有合适的索引,比如(customer_id, created_at),还能进一步提速),逻辑更紧凑,性能表现更稳定,尤其在数据量大的时候优势更明显。

内容的提问来源于stack exchange,提问作者ckg61386

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:13:25