skip to Main Content

I have a Users table (id, name, created_at) and a Transaction table(id, user_id, created_at, amount).
For each month, I would like to know the number of users who did not have any transaction in the 3 months interval before that month.
For example, for April 2022, the query would return number of users who did not have a transaction in January 2022, February 2022 and March 2022. And so on for every month.

Can I do this with a single MySQL query, and without PHP loop?

If I wanted it for April 2022 only, then I guess this would do the trick:

SELECT count(distinct(users.id)) FROM users 
INNER JOIN transactions 
    on users.id = transactions.user_id 
WHERE transactions.user_id NOT IN 
   (SELECT user_id FROM transactions WHERE created_at > "2022-01-01" AND created_at < "2022-04-01" );

How to get it for all months?

2

Answers


  1. SELECT count(*) 
    FROM users 
    WHERE NOT EXISTS (
        SELECT NULL
        FROM transactions 
        WHERE users.id = transactions.user_id 
          AND created_at > '2022-01-01' AND created_at < '2022-04-01'
        );
    
    Login or Signup to reply.
  2. In a normal situation, you would have a calendar table that, for examples, stores all starts of months over a wide period of time, like calendar(start_of_month).

    From there on, you can cross join the calendar with the users table to generate all possible combinations of months and customers (with respect to the user’s creation time). The last step is to check each user/month tuple for transations in the last 3 months.

    select c.start_of_month, count(*) as cnt_inactive_users
    from calendar c
    cross join users u 
    where not exists (
        select 1 
        from transactions t 
        where t.user_id = u.id 
            and t.created_at >= c.start_of_month - interval 3 month
            and t.created_at <  c.start_of_month
    )
    where c.start_of_month >= '2021-01-01' and c.start_of_month < '2022-01-01'
    group by c.start_of_month
    order by c.start_of_month
    

    This gives you one row per month that has at least one "inactive" customers,with the corresponding count.

    You control the range of months over which the query applies with the where clause to the query (as an example, the above gives you all year 2021).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search