Oracle SQL:按月检查客户新近度

时间:2018-08-03 16:58:53

标签: sql oracle plsql case

我有一个电子商务网站的order_list表,我需要从该表创建一个月内购买了多少客户的报告。在这些客户中,有多少是首次客户,在最近90天内有多少人下了订单,在最近180天内有多少人,等等。

完成的报告将是一个如下所示的excel网格:

Recency Grid Example

这是我现在拥有的查询:

SELECT months.month,
       count(distinct(case when months.month = Trunc (orders.order_date, 'MONTH') then orders.email_address else null end)) as total_monthly_orders,
       count(distinct(case when months.month = Trunc (orders.order_date, 'MONTH') and order_rank = 1 then orders.email_address else null end)) as monthly_first_purchasers,

       /* This is the logic thats not working right now*/
       /*count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 92 then orders.email_address else null end)) as less_than_3_month_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 181 then orders.email_address else null end)) as less_than_6_month_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 273 then orders.email_address else null end)) as less_than_9_month_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 365 then orders.email_address else null end)) as less_than_12_month_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) > 365 then orders.email_address else null end)) as one_year_plus_purchasers*/


FROM (  SELECT Trunc (TO_DATE (A.create_date), 'MONTH') AS month
            FROM ORDER_DETAIL A
           WHERE TO_DATE (A.create_date) >= '1-Jan-2018'
        GROUP BY Trunc (TO_DATE (A.create_date), 'MONTH')
        ORDER BY Trunc (TO_DATE (A.create_date), 'MONTH') ASC) months
INNER JOIN (SELECT A.EMAIL_ADDRESS,
               A.DEMANDWARE_ORDER_NUMBER AS order_id,
               TO_DATE (A.CREATE_DATE) AS order_date,
               RANK ()
               OVER (PARTITION BY A.EMAIL_ADDRESS
                     ORDER BY A.DEMANDWARE_ORDER_NUMBER ASC)
                  AS Order_rank
          FROM ORDER_DETAIL A
         WHERE A.email_address IS NOT NULL) orders
          ON months.month >= Trunc (orders.order_date, 'MONTH')

Group by months.month
Order by months.month ASC 

我测试了该查询,并正确地提取了总客户和首次使用的客户。但是我不知道该如何吸引最近一次购买是在过去3个月/ 6个月等之内的客户。

有人可以帮我吗?

编辑:添加样本数据 Current Query Output

我已经对其他查询进行了检查,“客户总数”和“首次客户”列中的值正确。但是其他列中的值不正确。本质上,要对此进行测试,每个存储桶中的客户总数应等于总客户数。

例如:如果1月份我们总共有34,016个客户,则<3个月存储桶中没有166,148个客户

3 个答案:

答案 0 :(得分:0)

如果我的理解正确,那么您的CASE WHEN需要检查月份号而不是日期号。

(months.month - (Trunc (orders.order_date, 'MONTH'))) <= 3

代替

(months.month - (Trunc (orders.order_date, 'MONTH'))) <= 92

然后,您需要在month子查询中添加查询列,以进行一年以上的判断。

使用EXTRACT列中的order_date

(EXTRACT(year FROM months.order_date) - EXTRACT(year FROM orders.order_date)) > 0

查询可能是这样的。

SELECT months.month,
       count(distinct(case when months.month = Trunc (orders.order_date, 'MONTH') then orders.email_address else null end)) as total_monthly_orders,
       count(distinct(case when months.month = Trunc (orders.order_date, 'MONTH') and order_rank = 1 then orders.email_address else null end)) as monthly_first_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 3 then orders.email_address else null end)) as less_than_3_month_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 6 then orders.email_address else null end)) as less_than_6_month_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 9 then orders.email_address else null end)) as less_than_9_month_purchasers,
       count(distinct(case when (months.month - (Trunc (orders.order_date, 'MONTH'))) <= 12 then orders.email_address else null end)) as less_than_12_month_purchasers,
       count(distinct(case when (EXTRACT(year FROM months.order_date) - EXTRACT(year FROM orders.order_date)) > 0 then orders.email_address else null end)) as one_year_plus_purchasers
FROM (  SELECT Trunc (TO_DATE (A.create_date), 'MONTH') AS month,
               TO_DATE (A.CREATE_DATE) order_date
            FROM ORDER_DETAIL A
           WHERE TO_DATE (A.create_date) >= '1-Jan-2018'
        GROUP BY Trunc (TO_DATE (A.create_date), 'MONTH')
        ORDER BY Trunc (TO_DATE (A.create_date), 'MONTH') ASC) months
INNER JOIN (SELECT A.EMAIL_ADDRESS,
               A.DEMANDWARE_ORDER_NUMBER AS order_id,
               TO_DATE (A.CREATE_DATE) AS order_date,
               RANK () OVER (PARTITION BY A.EMAIL_ADDRESS ORDER BY A.DEMANDWARE_ORDER_NUMBER ASC) AS Order_rank
          FROM ORDER_DETAIL A
         WHERE A.email_address IS NOT NULL
         ) orders
          ON months.month >= Trunc (orders.order_date, 'MONTH')
Group by months.month
Order by months.month ASC 

答案 1 :(得分:0)

如果我没看错,这可能会给你要点。创建一个二进制标志,以判断最后一个订单是否在最近几个月之内。

如果订单日期跨度多年,这将无法真正起作用,因此一旦您到2019年就会中断。但这很容易解决。我真的无法说出您要如何处理多年。

SELECT order_month,
       SUM(first_order) AS customerWithFirstOrder,
       SUM(within_three_months) AS customersWithinThreeMonths,
       SUM(within_six_months) AS customersWithinSixMonths
  FROM (SELECT DISTINCT 
               customer,
               case when prev_order_date IS NULL THEN 1 
                    ELSE 0 
                END first_order,
               case when prev_order_date >= DATE_ADD(month,order_month,-3) IS NULL 
                         THEN 1 ELSE 0 
                END within_three_months,
               case when prev_order_date >= DATE_ADD(month,order_month,-6) IS NULL 
                         THEN 1 
                    ELSE 0 
               END within_six_months,
               TRUNC(order_date, 'MONTH') order_month
          FROM (SELECT  LAG(TO_DATE(create_date)) OVER
                     (  PARTITION BY customer
                            ORDER BY TO_DATE(create_date)
                     )  AS prev_order_date,
                       customer,
                       TO_DATE(create_date) order_Date
                  FROM ORDER_DETAIL
                 WHERE TO_DATE (A.create_date) >= '1-Jan-2018'
               ) TMP
       );

答案 2 :(得分:0)

我根据用户用例创建了一个虚拟表,并根据您的要求编写了查询。查询非常简单。无需加入表2次。 下面是我的代码。

-表格创建

create table ORDER_DETAIL
(
create_date date, -- date on which customer created account.
EMAIL_ADDRESS varchar2(100),
DEMANDWARE_ORDER_NUMBER number, -- orderid
order_date date
);

-插入数据

insert into ORDER_DETAIL values (to_date('1-JAN-2018'),'xyz@gmail.com',1,sysdate);
insert into ORDER_DETAIL values (to_date('31-JAN-2018'),'xyz@gmail.com',4,sysdate);
insert into ORDER_DETAIL values (to_date('3-MAR-2018'),'xyz@gmail.com',2,sysdate-8);

-查询

select 
count(*) as count_per_month,
to_char(CREATE_DATE,'MON') as customer_perchase_month,
sum((case 
    when to_char(CREATE_DATE,'MON') = to_char(ORDER_DATE,'MON')
    then
        1
    else
        0
    end ))First_Time_Customer, 
sum((case
    when months_between(trunc(ORDER_DATE) , trunc(CREATE_DATE)) < 3 then
        1
    else
        0
   end )) less_than_3_months,

sum((case
    when months_between((trunc(ORDER_DATE)) , trunc(CREATE_DATE)) between 3 and 6  then
        1
    else
        0
   end )) less_than_6_months , 

sum((case
    when months_between((trunc(ORDER_DATE)) , trunc(CREATE_DATE)) between 6 and 12  then
        1
    else
        0
   end )) less_than_12_months,

   sum((case
    when months_between(trunc(ORDER_DATE) , trunc(CREATE_DATE)) > 12 then
        1
    else
        0
   end )) greater_than_12 

from
ORDER_DETAIL od
WHERE TO_DATE (create_date) >= '1-Jan-2018'
and EMAIL_ADDRESS is not null
group by to_char(CREATE_DATE,'MON');  

希望这可以解决您的要求。

关于Ankit。