如果您有索引orderdate
并希望使用此索引,我建议使用此查询(date_trunc函数很方便查找当前月份的第一天和上个月的第一天):
select c.id, c.name
from customers as c
where
not exists (
select *
from orders as o
where
o.cid = c.id and
o.orderdate >= date_trunc('month', (now() - '1 month'::interval)::timestamp) and
o.orderdate < date_trunc('month', now()::timestamp)
)
=> sql 小提琴演示
将此与 snyder 的答案进行比较,很清楚为什么在将列与过滤值进行比较之前在列上使用函数是不好的做法。
这是=>带有两个查询的 sql fiddle 演示。执行计划如下:
这个查询:
Nested Loop Anti Join (cost=0.02..2598.74 rows=160 width=222)
-> Seq Scan on customers c (cost=0.00..13.20 rows=320 width=222)
-> Index Only Scan using ix_orders on orders o (cost=0.02..8.07 rows=1 width=4)
Index Cond: ((cid = c.id) AND (orderdate >= date_trunc('month'::text, ((now() - '1 mon'::interval))::timestamp without time zone)) AND (orderdate < date_trunc('month'::text, (now())::timestamp without time zone)))
斯奈德:
Hash Anti Join (cost=30468.50..30523.40 rows=160 width=222)
Hash Cond: (a.id = b.cid)
-> Seq Scan on customers a (cost=0.00..13.20 rows=320 width=222)
-> Hash (cost=30406.00..30406.00 rows=5000 width=4)
-> Seq Scan on orders b (cost=0.00..30406.00 rows=5000 width=4)
Filter: (to_char((orderdate)::timestamp with time zone, 'Mon YYYY'::text) = to_char((now() - '1 mon'::interval), 'Mon YYYY'::text))