2017-02-16 66 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