计算 SQL 上给定事件的订户数量

Counting subscriber numbers given events on SQL

我在 mysql 上有一个格式如下的数据集,显示给定某些客户端 ID 的事件历史记录: Base Data

数据集文本 (subscriber_table):

user_id   type  created_at
A   past_due    2021-03-27 10:15:56
A   reactivate  2021-02-06 10:21:35
A   past_due    2021-01-27 10:30:41
A   new 2020-10-28 18:53:07
A   cancel  2020-07-22 9:48:54
A   reactivate  2020-07-22 9:48:53
A   cancel  2020-07-15 2:53:05
A   new 2020-06-20 20:24:18
B   reactivate  2020-06-14 10:57:50
B   past_due    2020-06-14 10:33:21
B   new 2020-06-11 10:21:24

date_table:

full_date
2020-05-01
2020-06-01
2020-07-01
2020-08-01
2020-09-01
2020-10-01
2020-11-01
2020-12-01
2021-01-01
2021-02-01
2021-03-01

我一直在努力想出一个查询来计算给定月份范围内的订阅者数量,事件中没有必要包含这些订阅者数量 table 要么是因为客户仍在订阅,要么是他们取消了,后来又取消了重新订阅。我正在寻找的输出是这样的:

Output

date    subscriber_count
2020-05-01  0
2020-06-01  2
2020-07-01  2
2020-08-01  1
2020-09-01  1
2020-10-01  2
2020-11-01  2
2020-12-01  2
2021-01-01  2
2021-02-01  2
2021-03-01  2

重新激活和逾期事件不会更改客户端的订阅状态,但只有取消和新建事件会更改。如果客户在一个月内取消,他们在该月仍应被视为活跃。

我最初的方法是获取每个订户 ID 一个月的最新条目,然后将它们加入预制日期 table,但是当我缺少几个月时,我不确定如何用正确的状态。也许是滞后函数?

with last_record_per_month as (
    select
date_trunc('month', created_at)::date order by created_at) as month_year ,
        user_id ,
        type,
        created_at as created_at
    from
        subscriber_table
    where
        user_id in ('A', 'B')
    order by
        created_at desc
    ), final as (
    select
        month_year,
        created_at,
        type
    from
        last_record_per_month lrpm
    right join (
        select
            date_trunc('month', full_date)::date as month_year
        from
            date_table
        where
            full_date between '2020-05-01' and '2021-03-31'
        group by
            1
        order by
            1
        ) dd
    on lrpm.created_at = dd.month_year
    and num = 1
    order by
        month_year
    )
select
    *
from
    final

我确实有一个预制的基础 table,其中包含多年中的每个日期都可以用作加入 table

非常感谢任何帮助

谢谢!

这里的方法是将具有新连接的订阅者行作为基础,并使用自连接将它们映射到取消的行。然后以日期 tables 为基础,根据用户数量聚合它们以获得结果。

SELECT full_date, COUNT(DISTINCT user_id) FROM date_tbl
LEFT JOIN(
SELECT new.user_id,new.type,new.created_at created_at_new,
IFNULL(cancel.created_at,CURRENT_DATE) created_at_cancel
FROM subscriber new 
LEFT JOIN subscriber cancel 
ON new.user_id=cancel.user_id
AND new.type='new' AND cancel.type='cancel'
AND new.created_at<= cancel.created_at
WHERE new.type IN('new'))s
ON DATE_FORMAT(s.created_at_new, '%Y-%m')<=DATE_FORMAT(full_date, '%Y-%m')
AND DATE_FORMAT(s.created_at_cancel, '%Y-%m')>=DATE_FORMAT(full_date, '%Y-%m')
GROUP BY 1

让我分解一些部分

  1. 首先,我们需要让订阅者 table 根据 user_id 自行加入,然后离开 table 行 'new' 和右边一个 'cancel' new.type='new' AND cancel.type='cancel'

  2. 新的应该总是在取消的行之前所以添加这个new.created_at<= cancel.created_at

  3. 因为我们只关心基础table中有new的行,所以我们过滤掉WHERE子句new.type IN('new')中的行。子查询的结果看起来像这样

  4. 然后我们可以用左连接加入这个子查询日期 table 这样 created_at_new 列的年份和月份总是小于等于 full_date DATE_FORMAT(s.created_at_new, '%Y-%m')<=DATE_FORMAT(full_date, '%Y-%m') 但大于取消日期。

  5. 最后我们根据 full_date 进行汇总并考虑用户的唯一计数

fiddle