SQL - запрос на возврат активных подписок в данный день - PullRequest
2 голосов
/ 24 февраля 2020

У меня есть таблица, которая показывает, когда пользователь подписывается на подписку и когда срок его членства истекает. Пользователь может приобрести новую подписку, даже если его текущая подписка действует.

userid|purchasedate|expirydate
1     |2019-01-01  |2019-02-01
2     |2019-01-02  |2019-02-02
3     |2019-01-03  |2019-02-03
3     |2019-01-04  |2019-03-03

Мне нужен запрос SQL, который будет GROUP BY на дату и возвращает количество активных подписок на эту дату. Так что это вернется:

date      |count
2019-01-01|1
2019-01-02|2
2019-01-03|3
2019-01-04|3

Ответы [ 3 ]

1 голос
/ 24 февраля 2020

Вам нужен список дат и count(distinct):

select d.dte, count(distinct t.userid) as num_users
from (select distinct purchase_date as dte from t) d left join
     t
     on d.dte >= t.dte and
        d.dte <= t.expiry_date
group by d.dte
order by d.dte;

РЕДАКТИРОВАТЬ:

BigQuery может быть непостоянным в отношении неравенств в предложении on. Вот еще один подход:

select dte, count(distinct t.userid) as num_users
from t cross join
     unnest(generate_date_array(t.purchase_date, t.expiry_date, interval 1 day)) dte
group by dte
order by dte;

Вы можете использовать предложение where для фильтрации до определенных дат.

1 голос
/ 24 февраля 2020

Ниже для BigQuery Standard SQL

#standardSQL
SELECT day, COUNT(DISTINCT userid) active_subscriptions 
FROM (SELECT AS STRUCT MIN(purchasedate) min_date, MAX(expirydate) max_date FROM `project.dataset.table`),
UNNEST(GENERATE_DATE_ARRAY(min_date, max_date)) day 
JOIN `project.dataset.table`
ON day BETWEEN purchasedate AND expirydate
GROUP BY day  

Вы можете проверить, поиграть с выше, используя фиктивные данные из вашего вопроса, как в примере ниже

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 1 userid, DATE '2019-01-01' purchasedate, DATE '2019-02-01' expirydate UNION ALL
  SELECT 2, '2019-01-02', '2019-02-02' UNION ALL
  SELECT 3, '2019-01-03', '2019-02-03' UNION ALL
  SELECT 3, '2019-01-04', '2019-03-03' 
)
SELECT day, COUNT(DISTINCT userid) active_subscriptions 
FROM (SELECT AS STRUCT MIN(purchasedate) min_date, MAX(expirydate) max_date FROM `project.dataset.table`),
UNNEST(GENERATE_DATE_ARRAY(min_date, max_date)) day 
JOIN `project.dataset.table`
ON day BETWEEN purchasedate AND expirydate
GROUP BY day

с выводом ниже

Row day         active_subscriptions     
1   2019-01-01  1    
2   2019-01-02  2    
3   2019-01-03  3    
4   2019-01-04  3    
5   2019-01-05  3    
6   2019-01-06  3    
... ...         ...
... ...         ...
31  2019-01-31  3    
32  2019-02-01  3    
33  2019-02-02  2    
34  2019-02-03  1    
35  2019-02-04  1    
... ...         ...
... ...         ...
61  2019-03-02  1    
62  2019-03-03  1    
0 голосов
/ 24 февраля 2020

Я создаю имя таблицы 'test_expirydate' и использую ваши данные, и эта работа

select
    tb1.expirydate,
    count(*) as total
from test_expirydate as tb1
left join (
    select
        expirydate
    from test_expirydate as tb2
    group by userid
) as tb2
on tb1.expirydate >= tb2.expirydate
group by tb1.expirydate

Я не уверен, работает ли она в другом случае или нет, но она подходит для текущих данных

О, я понимаю, что в левой колонке должна быть дата истечения срока действия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...