2017-04-05 191 views
1

這種情況的背景是,我想計算MRR(每月的經常性收入)的基於訂閱的業務,其中當銷售是由收入記錄,合同的時間段一起,通過有效的代表結束日期。如何使用SQL在可變時間段(每月,每年等)傳播收入?

的任務就是分裂收入爲合同期限,並彙總多個合同,從而可以顯示每月的收入。這也是一個很好的結果,也可以顯示客戶流失,即當合同結束並且沒有續約時發生的$損失。

數據的格式是這樣(忽略計費週期):

╔══════════════════════════════════╦══════════════════════════╦══════════════════════════╦════════════════╦═══════╗ 
║   account_id   ║  start_date  ║ effective_end_date ║ billing_period ║ price ║ 
╠══════════════════════════════════╬══════════════════════════╬══════════════════════════╬════════════════╬═══════╣ 
║ 2c92a0fd5286d62801528d6578230fa7 ║ 2015-10-01T00:00:00.000Z ║ 2017-10-15T00:00:00.000Z ║ Annual   ║ 1440 ║ 
║ 2c92a0fd5286d62801528d6578230fa8 ║ 2015-10-01T00:00:00.000Z ║ 2016-10-15T00:00:00.000Z ║ Annual   ║ 3500 ║ 
║ 2c92a0fd5286d62801528d6578230fa9 ║ 2015-10-01T00:00:00.000Z ║ 2015-12-31T00:00:00.000Z ║ Annual   ║ 700 ║ 
╚══════════════════════════════════╩══════════════════════════╩══════════════════════════╩════════════════╩═══════╝ 

期望的結果將顯示以下信息:

2c92a0fd5286d62801528d6578230fa7擴展$ 1440 24個月以上,從2015年10月至2017年10月。

2c92a0fd5286d62801528d6578230fa8從2015年10月至2016年10月,利差超過12個月$ 3500。

2c92a0fd5286d62801528d6578230fa9價差$ 700超過3個月,從2015年10月至12月2015年

我意識到我需要使用日期表CROSS JOIN,否則所有的日期將不會代表。我可以用CTE來做到這一點。但是,如何分配收入讓我更加不知所措。任何幫助,將不勝感激!

這是我已經得到了迄今:

SELECT account_id, date_trunc('month',effective_start_date) as start_date, effective_end_date, mrr as price, 
EXTRACT(YEAR FROM age(date_trunc('month',effective_end_date)::date,date_trunc('month', effective_start_date)::date))*12 + EXTRACT(month from age(date_trunc('month',effective_end_date)::date,date_trunc('month', effective_start_date)::date)) as contract_length_months, 
mrr/NULLIF(EXTRACT(YEAR FROM age(date_trunc('month',effective_end_date)::date,date_trunc('month', effective_start_date)::date))*12 + EXTRACT(month from age(date_trunc('month',effective_end_date)::date,date_trunc('month', effective_start_date)::date)),0) as divided_price 
FROM "public"."zuora_rate_plan_charge" where mrr <> 0 and mrr is not null 
order by date_trunc('month',effective_start_date) 

結果:

╔══════════════════════════════════╦══════════════════════════╦══════════════════════════╦═══════╦════════════════════════╦═══════════════╗ 
║   account_id   ║  start_date  ║ effective_end_date ║ price ║ contract_length_months ║ divided_price ║ 
╠══════════════════════════════════╬══════════════════════════╬══════════════════════════╬═══════╬════════════════════════╬═══════════════╣ 
║ 2c92a0fd5286d62801528d6578230fa7 ║ 2015-10-01T00:00:00.000Z ║ 2017-10-15T00:00:00.000Z ║ 1440 ║      24 ║   60 ║ 
╚══════════════════════════════════╩══════════════════════════╩══════════════════════════╩═══════╩════════════════════════╩═══════════════╝ 

所需的結果:

╔════════╦════════════════╗ 
║ Month ║  MRR  ║ 
╠════════╬════════════════╣ 
║ Oct 15 ║ 585   ║ 
║ Nov 15 ║ 585   ║ 
║ Dec 15 ║ 585   ║ 
║ Jan 16 ║ 351.6666666667 ║ 
╚════════╩════════════════╝ 

回答

0

您可以使用generate_series()拿到個月,然後一些算法來獲取數據。爲了讓所有的月供一個客戶:

select yyyymm, sum(monthly) 
from (select t.*, 
      price/count(*) over (partition by account_id) as monthly 
     from (select t.*, 
        generate_series(start_date, end_date, interval '1 month') as yyyymm 
      from t 
      ) t 
    ) t 
group by yyyymm 
order by yyyymm; 

select t.*, price/count(*) over (partition by account_id) as monthy 
from (select t.*, 
      generate_series(start_date, end_date, interval '1 month') as yyyymm 
     from t 
    ) t; 

然後,你可以,如果你想每個月的金額彙總此

0

下面是一些提示,可能有幫助。這個想法很簡單,你可以簡單地製作只有YEAR-MONTH的虛擬表,然後加入它來獲得你想要的數據。

  1. 在這種情況下,我用來製造假表加入其中只有年月柱 前)2012-02,2012-03,2012-04,2020-12 ~~~
  2. 這裏是簡單的查詢來獲得每個月的價格。 前)SELECT價格/ TIMESTAMPDIFF(月,日期,結束日期)工資,日期,結束日期從TestTable的
  3. 加入(1)表和你的結果,並通過(1)列按組拿到的薪水..

祝你好運。