简体   繁体   中英

Calculate Running total of active users by groups

I need to find the running total of active users in the system based on the groups If a user is currently suspended he shouldn't be considered in the current count but should be considered when he was active For Ex A user got suspended in april 2019 so he should be considered as a active user till all the counts in march

The users table contains the status ('Active'/'Suspended') and updatedon column I have written the code but it doesn't give me the desired result as it only considers the current active users

 SELECT DISTINCT Concat(year(b1.created_at),'-',monthname(b1.created_at)) Date,c1.name as 'GroupName',
(   
    select 
    count(distinct(b.user_id))      from 
        users u2 join teams_users b on u2.id = b.user_id join teams c on b.team_id = c.id  
    where 
    year(b.created_at)*100 + month(b.created_at) <= year(b1.created_at)*100+month(b1.created_at)
     and 
    u2.organization_id =1690 
             and u2.status = 'Active' 
    and c.organization_id = 1690 
     and c.id =c1.id
    ) total_users
 from users u1 join teams_users b1 on u1.id = b1.user_id 
 join teams c1 on b1.team_id = c1.id
 where 
     u1.organization_id =1690  and u1.status = 'Active'

Users

 UserId|CreatedOn|Status|Updatedon

Teams

 Id|Name

Team_users

 Team_id|User_id|CreatedOn

Here's a sample query that will get you a total number of users in a given month, per month, per team:

with generator as
(
SELECT 0 n 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   UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
   SELECT 12  
),
user_to_team as
(
   select user_id
        , team_id
        , tu.created_at as date_joined
        , case 
            when u.status = 'suspended'
            then u.updatedon
            else curdate()
          end member_until
     from team_users tu
     join users u
       on u.id = tu.user_id
), periods as
(
   select year*100 + month as period
     from (select 2018+n as year from generator where n < 2) x
    cross
     join (select 1+n as month from generator where n<12) y
)
select periods.period
     , t.id
     , count(u2t.user_id)
  from periods
  join teams t
    on year(t.created_at) * 100 + month(t.created_at) <= periods.period
  left outer
  join user_to_team u2t
    on periods.period between year(u2t.date_joined)*100 + month(u2t.date_joined) and year(u2t.member_until)*100 + month(u2t.member_until)
   and u2t.team_id = t.id
 where periods.period <= year(curdate())*100 + month(curdate())
group by periods.period, t.id
order by periods.period, t.id

generator CTE is for generating numbers, we'll need that in periods to generate a list of year-months ( yyyymm ). If you have a numbers table, you can use that. user_to_team CTE just lists the relations between users with when they joined (record in user_teams created) and until when they were members (either updatedon of the user if they are suspended, or current date). Then it's just a matter of joining our periods to teams and the user_to_team to that based on dates - teams are joined ever since they were created and members to period between which they existed.

Here's a working sample on dbfiddle

There are two teams:

  • team 1 created in 2019-01
  • team 2 created in 2019-02

Users:

  • user 1, active
  • user 2, suspended since 2019-03

Team to User:

  • user 1 in team 1 since 2019-01, in team 2 since 2019-03
  • user 2 in team 1 since 2019-03, in team 2 since 2019-03

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM