2017-02-16 75 views
2

说你有客户的使用日期表如下:
[CUSTOMER_TABLE]的Oracle SQL以往X日选择不同的客户滚动周期

+----------+-----------+----------+ 
| customer | date  | purchase | 
+----------+-----------+----------+ 
| 1  | 1/01/2016 | 12  | 
+----------+-----------+----------+ 
| 1  | 1/12/2016 | 3  | 
+----------+-----------+----------+ 
| 2  | 5/03/2016 | 5  | 
+----------+-----------+----------+ 
| 3  | 1/16/2016 | 6  | 
+----------+-----------+----------+ 
| 3  | 3/22/2016 | 1  | 
+----------+-----------+----------+ 

我想编写一个查询来算多少不同的客户在过去的10天内作为一个滚动周期进行了购买,从每个日历日开始计算并且向后计数10天。因此,对于每一个独特的一天在2016年最后的结果将是一个日历,其中的每一天都有存在类似下面的日历当天的10天前不同客户的计数:
[result_table]

+-----------+------------------+ 
| date  | unique customers | 
+-----------+------------------+ 
| 1/01/2016 | 112    | 
+-----------+------------------+ 
| 1/02/2016 | 104    | 
+-----------+------------------+ 
| 1/03/2016 | 140    | 
+-----------+------------------+ 
| 1/04/2016 | 133    | 
+-----------+------------------+ 
| ....  | 121    | 
+-----------+------------------+ 

我想出的一个解决方案是创建一个单列日历表,然后通过不平等连接将日历表连接到客户表。我相信这是非常低效的,并且正在寻求更快的解决方案。所以我的第一步是创建一个像这样一个日程表:
[日历]

+-----------+ 
| date  | 
+-----------+ 
| 1/01/2016 | 
+-----------+ 
| 1/02/2016 | 
+-----------+ 
| 1/03/2016 | 
+-----------+ 
| 1/04/2016 | 
+-----------+ 
| 1/05/2016 | 
+-----------+ 

然后每天在日历,事先算组不同客户的每一天,我喜欢这样的不平等加盟:

select 
count(distinct customer) as unique customers 
from calendar c 
left join mytable m 
on c.date>=m.date and m.date>=c.date-10 

虽然我认为这是正确的,但运行速度非常缓慢(比如说有两百万用户的日历)。有没有一个oracle分析函数可以帮助我在这里?

+0

你能提供一些示例数据和输出?我有几个想法我想测试...... – BobC

+0

总共有多少条记录在mytable中?桌上有几个不同的客户? – nop77svk

+0

数据是敏感的对不起,我在两年的日历上运行这个不到1000万但超过500,000不同的客户。 – barker

回答

3

是否有一个oracle分析函数可以帮助我在这里?

不是真的 - 从COUNT() documentation

如果指定DISTINCT,那么你可以指定analytic_clause的只有query_partition_clause。不允许使用order_by_clausewindowing_clause

你会希望DISTINCTwindowing_clause这是不允许的。

更新

你可以为使用非DISTINCT分析查询的组合无效语法按客户划分相同的效果,然后按天聚合:

甲骨文设置

CREATE TABLE table_name (customer, dt) AS 
    SELECT 1, DATE '2017-01-10' FROM DUAL UNION ALL 
    SELECT 1, DATE '2017-01-11' FROM DUAL UNION ALL 
    SELECT 1, DATE '2017-01-15' FROM DUAL UNION ALL 
    SELECT 1, DATE '2017-01-20' FROM DUAL UNION ALL 
    SELECT 2, DATE '2017-01-12' FROM DUAL UNION ALL 
    SELECT 2, DATE '2017-01-19' FROM DUAL UNION ALL 
    SELECT 3, DATE '2017-01-10' FROM DUAL UNION ALL 
    SELECT 3, DATE '2017-01-13' FROM DUAL UNION ALL 
    SELECT 3, DATE '2017-01-15' FROM DUAL UNION ALL 
    SELECT 3, DATE '2017-01-20' FROM DUAL; 

查询

注意:以下查询仅用于一个月的数据,前两天的范围用于说明原理,但很容易将参数更改为12个月和10天。

SELECT day, 
     SUM(has_order_in_range) AS unique_customers 
FROM (
    SELECT customer, 
     day, 
     LEAST(
      1, 
      COUNT(dt) OVER (PARTITION BY customer 
          ORDER BY day 
          RANGE BETWEEN INTERVAL '2' DAY PRECEDING 
             AND INTERVAL '0' DAY FOLLOWING) 
     ) AS has_order_in_range 
    FROM table_name t 
     PARTITION BY (customer) 
     RIGHT OUTER JOIN 
     (-- Create a calendar for one month 
      SELECT DATE '2017-01-01' + LEVEL - 1 AS day 
      FROM DUAL 
      CONNECT BY DATE '2017-01-01' + LEVEL - 1 < ADD_MONTHS(DATE '2017-01-01', 1) 
     ) d 
     ON (t.dt = d.day) 
) 
GROUP BY day 
ORDER BY day; 

输出

DAY     UNIQUE_CUSTOMERS 
------------------- ---------------- 
2017-01-01 00:00:00    0 
2017-01-02 00:00:00    0 
2017-01-03 00:00:00    0 
2017-01-04 00:00:00    0 
2017-01-05 00:00:00    0 
2017-01-06 00:00:00    0 
2017-01-07 00:00:00    0 
2017-01-08 00:00:00    0 
2017-01-09 00:00:00    0 
2017-01-10 00:00:00    2 
2017-01-11 00:00:00    2 
2017-01-12 00:00:00    3 
2017-01-13 00:00:00    3 
2017-01-14 00:00:00    2 
2017-01-15 00:00:00    2 
2017-01-16 00:00:00    2 
2017-01-17 00:00:00    2 
2017-01-18 00:00:00    0 
2017-01-19 00:00:00    1 
2017-01-20 00:00:00    3 
2017-01-21 00:00:00    3 
2017-01-22 00:00:00    2 
2017-01-23 00:00:00    0 
2017-01-24 00:00:00    0 
2017-01-25 00:00:00    0 
2017-01-26 00:00:00    0 
2017-01-27 00:00:00    0 
2017-01-28 00:00:00    0 
2017-01-29 00:00:00    0 
2017-01-30 00:00:00    0 
2017-01-31 00:00:00    0 
+0

所以你认为唯一的方法是三角形连接/交叉连接? – barker

+0

@barker通过分析和聚合函数和分区连接的组合找到了一种方法......没有关于它如何执行的说法,与范围条件下的外连接相比,因此您需要分析查询和比较。 – MT0

+0

我跑出TEMP尝试此查询。但它很聪明,很好。 – nop77svk