差距为

时间:2017-10-16 18:23:21

标签: sql postgresql

我的下表包含了除黄色之外的所有列

enter image description here

基本上,该表格包含客户的ID,销售日期以及当天客户支出的总金额(销售额)。现在,我必须计算当天每位客户的累计销售额,包括当天的销售额。例如,将时间范围设置为3天客户2233购买两次(14日没有),因此他在15日的累计销售额为26,而在13日他们是25。

我无法创建新表,因此我尝试了这种方法,但速度很慢

SELECT t.dt,

Count(CASE WHEN t.running_sale < 1.99 THEN 1 ELSE NULL END) as "Low spender",
Count(CASE WHEN t.running_sale BETWEEN 1.99 and 4.99 THEN 1 ELSE NULL END) as "Medium spender",
Count(CASE WHEN t.running_sale > 4.99 THEN 1 ELSE NULL END) as "High spender"

FROM  ( SELECT dt, channel, id, (
     SELECT SUM(revenue)
     FROM  myTable rd
     WHERE CAST(rd.dt AS DATE) 
             BETWEEN (CAST(rd.dt AS DATE) - INTERVAL '3' DAY) AND CAST(rd.dt AS DATE) AND 
           rd.id = r.id 
  ) running_sale from myTable r) t

WHERE channel = 'retail' 
AND dt BETWEEN '2017-06-01' AND '2017-06-15'

GROUP BY dt
limit 100

3 个答案:

答案 0 :(得分:2)

我会使用子查询来实现这个

select *,
  (
     select sum(sales)
     from your_table dd
     where cast(dd.dates as date) 
             between cast(your_table.dates as date) - interval '3' day and 
                     cast(your_table.dates as date) and 
           dd.id = your_table.id
  ) running_sales
from your_table

demo

并且可以将上述查询重写为更有效的对应方,只需使用自联接和group by

 select dd.id, dd.dates, dd.sales, sum(d.sales) running_sales
 from your_table dd
 join your_table d on cast(d.dates as date) 
         between (cast(dd.dates as date) - interval '3' day) and cast(dd.dates as date) and 
       dd.id = d.id
 group by dd.id, dd.dates, dd.sales

group by demo

您可以考虑创建以下索引以支持上述查询:

create index ix_your_table on your_table(id, dates, sales)

答案 1 :(得分:0)

With CTE as (
    SELECT 1234 id, '2017-06-15' idate,9 sales from dual UNION ALL
    SELECT 2233 id, '2017-06-03' idate,20 sales from dual UNION ALL
    SELECT 2233 id , '2017-06-05' idate,4 sales from dual UNION ALL
    SELECT 2233 id , '2017-06-06' idate,1 sales from dual UNION ALL
    SELECT 2233 id , '2017-06-11' idate,8 sales from dual UNION ALL
    SELECT 2233 id , '2017-06-12' idate,4 sales from dual UNION ALL
    SELECT 2233 id, '2017-06-13' idate,21 sales from dual UNION ALL
    SELECT 2233 id, '2017-06-15' idate,1 sales from dual UNION ALL
    SELECT 2544 id , '2017-06-13' idate,9 sales from dual UNION ALL
    SELECT 2443 id, '2017-06-05' idate,3.5 sales from dual )

 ,cte2 as (
select cte.*, to_number(replace(idate,'-')) datekey from cte
 )
 --select * from cte2
--SELECT cte.*, sum(cte.Sales) OVER (PARTITION by ID ORDER BY cte.iDate asc ROWS 2 PRECEDING ) as RunningSales FROM CTE

 --select rownum rn from dual connect by prior
 ,pp as (
 SELECT to_number(dd+20170600) dkey
FROM   ( SELECT rownum dd
         FROM   dual
         CONNECT BY LEVEL <= 31 
       )
)
--select * from pp
,cc as (


select cte2.* ,pp.dkey 
from pp left join cte2 
on(cte2.datekey=pp.dkey)
)
select cc.* ,sum(cc.Sales) OVER (PARTITION by cc.ID ORDER BY cc.dkey asc ROWS 2 PRECEDING ) as RunningSales
from cc order by dkey asc ,id asc

答案 2 :(得分:0)

如果每天最多只有一次销售,那么最有效的方法可能会重复滞后:

select rd.*,
       (sales +
        (case when prev_date >= date - interval '2 day' then prev_sales else 0 end) + 
        (case when prev2_date >= date - interval '2 day' then prev2_sales else 0 end)
       ) as sales_3day
from (select rd.*,
             lag(date, 1) over (partition by id order by date) as prev_date,
             lag(date, 2) over (partition by id order by date) as prev_date2,
             lag(sales, 1) over (partition by id order by date) as prev_sales,
             lag(sales, 2) over (partition by id order by date) as prev_sales2
      from mytable rd
) rd;

获得此值后,其余部分只是结果的条件逻辑。

如果您在一个日期有多个销售,则可以通过在最里面的查询中进行汇总来轻松完成此工作。