按日期计算和转动表格

时间:2016-09-06 09:49:15

标签: sql oracle analytics sqlreportingservice

我想从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

我想它会使用带有无界跟随和前置子句的窗口子句的分区...但我找不到任何合适的例子。 有任何想法吗...? 感谢

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

Oracle安装程序

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 

答案 2 :(得分: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  |           |           |           |           |