Postgresql - 你可以在没有CTE的情况下做到这一点吗?

时间:2015-10-30 20:12:19

标签: sql postgresql

我想知道客户在最初订购后的前7天内的订单和金额。我设法用一个公用表表达式来做,但很想知道是否有人可以指出对主查询的WHERE或HAVING部分或者子查询的明显更新。

--This is a temp table to use in the main query
WITH first_seven AS 

    (
    select min(o.created_at), min(o.created_at) + INTERVAL '7 day' as max_order_date, o.user_id
    from orders o
    where o.total_price > 0 and o.status = 30
    group by o.user_id
    having min(o.created_at) > '2015-09-01' 
    )


--This is the main query, find orders in first 7 days of purchasing

SELECT sum(o.total_price) as sales, count(distinct o.objectid) as orders, o.user_id, min(o.created_at) as first_order
from orders o, first_seven f7 
where o.user_id = f7.user_id and o.created_at < f7.max_order_date and o.total_price > 0 and o.status = 30
group by o.user_id
having min(o.created_at) > '2015-09-01'

1 个答案:

答案 0 :(得分:0)

您可以使用窗口函数在没有join的情况下执行此操作:

select sum(o.total_price) as sales, count(distinct o.objectid) as orders,
       o.user_id, min(o.created_at) as first_order
from (select o.*,
             min(o.created_at) over (partition by user_id) as startdate
      from orders o
      where o.total_price > 0 and o.status = 30 
     ) o
where startdate > '2015-09-01' and
      created_at <= startdate + INTERVAL '7 day';

更复杂的查询(使用正确的索引)可能更有效:

select sum(o.total_price) as sales, count(distinct o.objectid) as orders,
       o.user_id, min(o.created_at) as first_order
from (select o.*,
             min(o.created_at) over (partition by user_id) as startdate
      from orders o
      where o.total_price > 0 and o.status = 30 and
            not exists (select 1 from orders o2 where o2.user_id = o.user_id and created_at <= '2015-09-01')
     ) o
where startdate > '2015-09-01' and
      created_at <= startdate + INTERVAL '7 day';

这会在Windows计算之前过滤掉旧客户,这样可以提高效率。有用的索引是orders(user_id, created_at)orders(status, total_price)