SQL как мы можем получить месячный тренд из двух отдельных столбцов start_date и end_date? - PullRequest
0 голосов
/ 12 апреля 2020

Представьте, что у нас есть следующие данные:

ID,State,start_date,end_date,Product

S1,Trial,2020/01/01,2020/01/07,Hulu
S1,Paid,2020/01/08,2020/01/31,Hulu
S1,Expired,2020/02/01,null,Hulu
S1,Paid,2020/03/01,2020/03/30,Hulu
S2,Paid,2020/01/08,2020/01/31,Hulu
S3,Paid,2020/01/09,2020/02/01,Hulu

create table test
  (
  ID varchar(10),
  State varchar(10),
  start_date datetime,
  end_date datetime,
  Product varchar(10)
  );

 insert into test 
 VALUES 
('S1','Trial','2020-01-01','2020-01-07','Hulu'),
('S1','Paid','2020-01-08','2020-01-31','Hulu'),
('S1','Expired','2020-02-01',null,'Hulu'),
('S1','Paid','2020-03-01','2020-03-30','Hulu'),
('S2','Paid','2020-01-08','2020-01-31','Hulu'),
('S3','Paid','2020-01-09','2020-02-01','Hulu')
 ;

Вопрос здесь в том, чтобы получить месячную тенденцию 2020 активных платных подписок. Для каждого подписчика (ID) мы можем подсчитать только месяцы, в течение которых они активны. Таким образом, для S1 мы можем считать S1 активным только в январе 2020 и марте 2020 года, а не в феврале 2020 года.

Во время интервью я написал функцию и сказал, что мы можем l oop вызывать эту функцию для каждого месяц в 2020

def month_active_sub($yyyymm):
   select 
   $yyyymm as month,
   count(distinct ID)
   from table where end_date >= $yyyymm and start_date <= $yyyymm and state='paid';

или

   select 
   '202001' as month,
   count(distinct ID)
   from table where end_date >= '202001' and start_date <= '202001' and state='paid'

   union all 

   select 
   '202002' as month,
   count(distinct ID)
   from table where end_date >= '202002' and start_date <= '202002' and state='paid'

   union all for another 10 months

Интересно, есть ли лучший способ написать этот SQL запрос? Спасибо!

1 Ответ

1 голос
/ 12 апреля 2020

Один метод использует таблицу чисел:

select '2020-01-01' + interval n.n month start_of_month, count(t.id) no_active_subscribers
from (
    select 0 n 
    union all select 1
    union all select 2 
    ... 
    union all select 11
) n
left join mytable t 
    on  t.start_date >= '2020-01-01' + interval n.n month
    and t.end_date   <= '2020-01-01' + interval (n.n + 1) month
    and t.state = 'paid'
group by n.n
...