在过去90天内根据登录计算活跃用户数

时间:2016-03-09 14:00:37

标签: mysql

我正在尝试进行一个查询,该查询将显示一个列表,显示我们每月有多少活跃用户。我们将活跃用户定义为过去90天内已登录的用户。

我可以通过此

轻松定义我们现在拥有的活跃用户数
SELECT COUNT(DISTINCT(user_id) FROM login_table
WHERE login_date BETWEEN DATE_SUB(login_date, INTERVAL 90 DAY) AND NOW())

当我必须按月计算用户数量时,我的问题就出现了 在这里,我必须多次计算一次登录。

如果我的用户在1月10日登录,并且从未再次登录,则此用户在以下月份应计为活跃用户:1月,2月,3月和4月,即使我只有一个注册用户

示例数据:

login_date | user_id
2015-01-01 | 1
2015-02-10 | 1
2015-02-11 | 2
2015-02-13 | 1
2015-03-19 | 1

这应该是这样的:

Date    | Active users
2015-01 | 1 
2015-02 | 2
2015-03 | 2 
2015-04 | 2 
2015-05 | 2 
2015-06 | 1 
2015-07 | 0 
2015-08 | 0 

有没有做过这样的计数?

7 个答案:

答案 0 :(得分:2)

你能用:

Select DATE_FORMAT(login_date,'%Y %m') as date, ....
....    
Group by DATE_FORMAT(login_date,'%Y %m')

答案 1 :(得分:2)

您可以构建一个包含所有所需月/年值对的内联计数表。然后LEFT JOIN将您的表格添加到此表格并GROUP BY以获得所需的结果:

SELECT CONCAT(months.m, '-', years.y) AS 'date', 
       COUNT(DISTINCT(user_id)) AS 'users_count'
FROM (
   SELECT '01' AS m UNION ALL SELECT '02' UNION ALL SELECT '03' UNION ALL 
   SELECT '04' UNION ALL SELECT '05' UNION ALL SELECT '06' UNION ALL 
   SELECT '07' UNION ALL SELECT '08' UNION ALL SELECT '09' UNION ALL 
   SELECT '10' UNION ALL SELECT '11' UNION ALL SELECT '12') AS months
CROSS JOIN (
   SELECT '2015' AS y UNION ALL SELECT '2016') AS years
LEFT JOIN login_table AS lt
   ON DATE_FORMAT(lt.login_date, '%d-%Y') = CONCAT(months.m, '-', years.y)
GROUP BY CONCAT(months.m, '-', years.y)

上述查询适用于生成2015/2016年所有月份的报告。您可以根据需要编辑计数表,以使其适应您的实际要求。

修改

如果您想在滚动 3个月间隔内计算活动用户,则需要关联:

SELECT CONCAT(months.m, '-', years.y) AS 'date', 
       (SELECT COUNT(DISTINCT(user_id)) 
        FROM login_table
        WHERE login_date BETWEEN CONCAT(years.y, '-', months.m, '-01') AND 
                                 DATE_ADD(CONCAT(years.y, '-', months.m, '-01'), INTERVAL 90 DAY))
FROM (
   SELECT '01' AS m UNION ALL SELECT '02' UNION ALL SELECT '03' UNION ALL 
   SELECT '04' UNION ALL SELECT '05' UNION ALL SELECT '06' UNION ALL 
   SELECT '07' UNION ALL SELECT '08' UNION ALL SELECT '09' UNION ALL 
   SELECT '10' UNION ALL SELECT '11' UNION ALL SELECT '12') AS months
CROSS JOIN (
   SELECT '2015' AS y UNION ALL SELECT '2016') AS years
LEFT JOIN login_table AS lt
   ON DATE_FORMAT(lt.login_date, '%d-%Y') = CONCAT(months.m, '-', years.y)
GROUP BY CONCAT(months.m, '-', years.y)

答案 2 :(得分:2)

如果您的日历表包含所需的所有日期,则此类问题更容易解决。如果您没有这样的表,可以使用如下查询创建它:

create table `calendar` (
    `date` DATE NOT NULL,
    PRIMARY KEY (`date`)
)  
    select DATE_ADD('1900-01-01',INTERVAL t4.c*10000 + t3.c*1000 + t2.c*100 + t1.c*10 + t0.c DAY) as `date`
    from 
    (select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t0,
    (select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t1,
    (select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2,
    (select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3,
    (select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4

这将创建一个日期为1900-01-01到2173-10-15(100K天)的表,并且只消耗大约2.5 MB。您可以根据自己的需要进行调整。

使用caledar表可以获得三个月的范围:

select 
    DATE_FORMAT(date_sub(c.date, INTERVAL 1 day), '%Y-%m') as month,
    date_sub(c.date, INTERVAL 3 month) as first_day,
    date_sub(c.date, INTERVAL 1 day)   as last_day
from calendar c
where day(c.date) = 1
  and c.date between '2015-02-01' and '2015-09-01'

结果:

| month   | first_day  | last_day   |
| 2015-01 | 2014-11-01 | 2015-01-31 |
| 2015-02 | 2014-12-01 | 2015-02-28 |
| 2015-03 | 2015-01-01 | 2015-03-31 |
| 2015-04 | 2015-02-01 | 2015-04-30 |
| 2015-05 | 2015-03-01 | 2015-05-31 |
| 2015-06 | 2015-04-01 | 2015-06-30 |
| 2015-07 | 2015-05-01 | 2015-07-31 |
| 2015-08 | 2015-06-01 | 2015-08-31 |

调整它,如果你真的想要使用90天的间隔。

现在,这是一个简单的左连接,使用登录表来获得你想要的东西:

select i.month as `Date`, count(distinct l.user_id) as `Active users`
from (
    select 
        date_format(date_sub(c.date, interval 1 day), '%Y-%m') as month,
        date_sub(c.date, interval 3 month) as first_day,
        date_sub(c.date, interval 1 day)   as last_day
    from calendar c
    where day(c.date) = 1
      and c.date between '2015-02-01' and '2015-09-01'
) i
left join login_table l on l.login_date between i.first_day and i.last_day
group by i.month

http://sqlfiddle.com/#!9/d1bb0/3

答案 3 :(得分:0)

并使用方法MONTH()?

类似的东西:

SELECT MONTH(login-date) as perMonth, COUNT(DISTINCT(user_id)) from login_table GROUP BY MONTH(login-date)

答案 4 :(得分:0)

SELECT Date_format(login_date, '%Y-%m-%01') as mymonth, count(user_id) as totalusers 
FROM login_table
WHERE login_date >= DATE_SUB(now(), INTERVAL 90 DAY)
Group by Date_format(login_date, '%Y-%m-%01')

以下是有关date_format函数https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format

的信息

答案 5 :(得分:0)

这将有效:

SELECT DATE_FORMAT(login_date, "%Y-%m"), COUNT(user_id)
FROM login_table
WHERE login_date BETWEEN DATE_SUB(login_date, INTERVAL 90 DAY) AND NOW()
GROUP BY login_date

答案 6 :(得分:0)

另一个简单而愚蠢的解决方案是每次向login_table复制login_date六次,每次增加15天。这样,我们可以确保在接下来的90天内每个月至少重复一次登录。然后我们可以按年份和飞蛾分组以计算活跃用户。

select 
    date_format(login_date, "%Y-%m") as `Date`,
    count(distinct l.user_id) as `Active users`
from (
    select l.user_id, l.login_date from login_table l
    union all select l.user_id, date_add(l.login_date, interval 15 day) from login_table l
    union all select l.user_id, date_add(l.login_date, interval 30 day) from login_table l
    union all select l.user_id, date_add(l.login_date, interval 45 day) from login_table l
    union all select l.user_id, date_add(l.login_date, interval 60 day) from login_table l
    union all select l.user_id, date_add(l.login_date, interval 75 day) from login_table l
    union all select l.user_id, date_add(l.login_date, interval 90 day) from login_table l
) l
group by date_format(login_date, "%Y-%m")