4

我想从这样的 Oracle(11g) 表中识别回头客:

CustID | Date
-------|----------
XC321  | 2016-04-28
AV626  | 2016-05-18
DX970  | 2016-06-23
XC321  | 2016-05-28
XC321  | 2016-06-02

所以我可以看到哪些客户在不同的窗口内返回,例如在 10、20、30、40 或 50 天内。例如:

CustID | 10_day | 20_day | 30_day | 40_day | 50_day 
-------|--------|--------|--------|--------|--------
XC321  |        |        |    1   |        |        
XC321  |        |        |        |    1   |        

我什至会接受这样的结果:

CustID |    Date    | days_from_last_visit
-------|------------|---------------------
XC321  | 2016-05-28 |                   30        
XC321  | 2016-06-02 |                    5

我想它会使用带有无限后续和前面子句的窗口子句进行分区......但我找不到任何合适的例子。有任何想法吗...?谢谢

4

3 回答 3

2

这里不需要窗口函数,您可以使用条件聚合简单地使用CASE EXPRESSION

SELECT t.custID,
       COUNT(CASE WHEN (last_visit- t.date) <= 10 THEN 1 END) as 10_day,
       COUNT(CASE WHEN (last_visit- t.date) between 11 and 20 THEN 1 END) as 20_day,
       COUNT(CASE WHEN (last_visit- t.date) between 21 and 30 THEN 1 END) as 30_day,
       .....
FROM (SELECT s.custID,
             LEAD(s.date) OVER(PARTITION BY s.custID ORDER BY s.date DESC) as last_visit
      FROM YourTable s) t
GROUP BY t.custID
于 2016-09-06T09:55:08.313 回答
1

甲骨文设置

CREATE TABLE customers ( CustID, Activity_Date ) AS
SELECT 'XC321', DATE '2016-04-28' FROM DUAL UNION ALL
SELECT 'AV626', DATE '2016-05-18' FROM DUAL UNION ALL
SELECT 'DX970', DATE '2016-06-23' FROM DUAL UNION ALL
SELECT 'XC321', DATE '2016-05-28' FROM DUAL UNION ALL
SELECT 'XC321', DATE '2016-06-02' FROM DUAL;

查询

SELECT *
FROM   (
  SELECT CustID,
         Activity_Date AS First_Date,
         COUNT(1) OVER ( PARTITION BY CustID
                         ORDER BY Activity_Date
                         RANGE BETWEEN CURRENT ROW AND INTERVAL '10' DAY FOLLOWING )
           - 1 AS "10_Day",
         COUNT(1) OVER ( PARTITION BY CustID
                         ORDER BY Activity_Date
                         RANGE BETWEEN CURRENT ROW AND INTERVAL '20' DAY FOLLOWING )
           - 1 AS "20_Day",
         COUNT(1) OVER ( PARTITION BY CustID
                         ORDER BY Activity_Date
                         RANGE BETWEEN CURRENT ROW AND INTERVAL '30' DAY FOLLOWING )
           - 1 AS "30_Day",
         COUNT(1) OVER ( PARTITION BY CustID
                         ORDER BY Activity_Date
                         RANGE BETWEEN CURRENT ROW AND INTERVAL '40' DAY FOLLOWING )
           - 1 AS "40_Day",
         COUNT(1) OVER ( PARTITION BY CustID
                         ORDER BY Activity_Date
                         RANGE BETWEEN CURRENT ROW AND INTERVAL '50' DAY FOLLOWING )
           - 1 AS "50_Day",
        ROW_NUMBER() OVER ( PARTITION BY CustID ORDER BY Activity_Date ) AS rn
  FROM  Customers
)
WHERE rn = 1;

输出

USTID FIRST_DATE              10_Day     20_Day     30_Day     40_Day     50_Day         RN
------ ------------------- ---------- ---------- ---------- ---------- ---------- ----------
AV626  2016-05-18 00:00:00          0          0          0          0          0          1 
DX970  2016-06-23 00:00:00          0          0          0          0          0          1 
XC321  2016-04-28 00:00:00          0          0          1          2          2          1 
于 2016-09-06T10:55:23.813 回答
0

这是一个对我有用的答案,我基于您上面的答案,感谢 MT0 和 Sagi 的贡献:

SELECT CustID,
visit_date,
Prev_Visit ,
COUNT(  CASE    WHEN (Days_between_visits) <=10    THEN 1  END) AS "0-10_day" ,
COUNT(  CASE    WHEN (Days_between_visits) BETWEEN 11 AND 20    THEN 1  END) AS "11-20_day" ,
COUNT(  CASE    WHEN (Days_between_visits) BETWEEN 21 AND 30    THEN 1  END) AS "21-30_day" ,
COUNT(  CASE    WHEN (Days_between_visits) BETWEEN 31 AND 40    THEN 1  END) AS "31-40_day" ,
COUNT(  CASE    WHEN (Days_between_visits) BETWEEN 41 AND 50    THEN 1  END) AS "41-50_day" ,
COUNT(  CASE    WHEN (Days_between_visits) >50    THEN 1  END) AS "51+_day"
FROM
  (SELECT CustID,
  visit_date,
  Lead(T1.visit_date) over (partition BY T1.CustID order by T1.visit_date DESC) AS Prev_visit,
  visit_date - Lead(T1.visit_date) over (
                  partition BY T1.CustID order by T1.visit_date DESC) AS Days_between_visits
  FROM T1
) T2
WHERE Days_between_visits >0
GROUP BY T2.CustID ,
T2.visit_date ,
T2.Prev_visit ,
T2.Days_between_visits;

这将返回:

CUSTID | VISIT_DATE | PREV_VISIT | DAYS_BETWEEN_VISIT | 0-10_DAY | 11-20_DAY | 21-30_DAY | 31-40_DAY | 41-50_DAY | 51+DAY 
XC321  | 2016-05-28 | 2016-04-28 |                 30 |          |           |         1 |           |           |
XC321  | 2016-06-02 | 2016-05-28 |                  5 |       1  |           |           |           |           |
于 2016-09-06T12:36:05.453 回答