使用不匹配的行连接两个表

时间:2013-09-01 09:34:04

标签: sql postgresql

我有两张桌子。

一个表包含客户详细信息(即)

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

3 个答案:

答案 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)
    )

=> sql fiddle demo

将这一点与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))