我有两张桌子。
一个表包含客户详细信息(即)
id(customerid--primary key),name,email,phonenumber
其他表包含订单表(即)
id,customerid(foreign key),ordervalue,orderdate
我需要获得在8月份没有订购过去一个月(即)的客户列表。我怎么能这样做。
这是我试过的查询
select a.id,a.name,b.order_date from customers a
left join orders b
on a.id = b.customer_id
where b.order_date is null
答案 0 :(得分:3)
SELECT *
FROM customers c
WHERE NOT EXISTS (
SELECT *
FROM orders nx
WHERE nx.customer_id = c.id
AND nx.order_date BETWEEN '2013-08-01' AND '2013-08-31'
);
答案 1 :(得分:3)
此查询将提取尚未订购past one month from today
的客户:
SELECT a.id, a.name
FROM customers a
WHERE NOT EXISTS(SELECT *
FROM orders b
WHERE b.cid = a.id AND
orderdate BETWEEN now()- '1 month'::interval
AND now());
以下是SQLfiddle
但是,如果您希望更准确地指出上个月的订单,即1st of last month to last date of last month
,那么您可以使用:
SELECT a.id, a.name
FROM customers a
WHERE NOT EXISTS(SELECT *
FROM orders b
WHERE b.cid = a.id AND
to_char(orderdate, 'Mon YYYY') =
to_char(now()- '1 month'::interval, 'Mon YYYY') );
以下是SQLfiddle
修改强>
请同时查看更有效的Roman Pekar's答案。
答案 2 :(得分:1)
如果您在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)
)
将这一点与snyder的答案进行比较,很明显为什么在将列上的函数与过滤值进行比较之前使用列上的函数是不好的做法。
这是=> sql fiddle demo,有两个查询。执行计划是:
此查询:
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))