Question

Lets say I have a user table which looks like

userID int(4) unsigned not null auto_increment,
name varchar(50) not null,
date_start int(10) unsigned not null,
date_stop int(10) unsigned not null

I want to count all users that were active (between date_start and date_stop, these are unix_timestamps()) per month.

So the result should be something like this :

2012/01    55
2012/02    58
2012/03    51

I'd say something like this, but obviously I'm missing something :

SELECT 
    DATE_FORMAT(???, '%Y/%m'), 
    COUNT(userID) 
FROM users 
WHERE 
    ??? BETWEEN date_start AND date_stop 
GROUP BY DATE_FORMAT(???, '%Y%m');

... just to clarify, what worked for me was :

SELECT m.yearMonth, COUNT(u.userID) 
FROM users u 
LEFT JOIN months m ON m.yearMonth BETWEEN DATE_FORMAT(FROM_UNIXTIME(u.date_start), '%Y%m') AND DATE_FORMAT(FROM_UNIXTIME(u.date_stop), '%Y%m') 
GROUP BY m.yearMonth;

Using a table that has "all" year/months stored in the form of yyyymm.

Was it helpful?

Solution

Firstly, you should have a table that contains the year, month details in yyyyMM format. Then you would need to join that table with the users table with yyyyMM portion of date_start less than the value in the months table and date_end greater than or equal to the value in the months table.

This would count a user who was active for more than one month, once per each month, which I think is what you expect.

CREATE TABLE months(yearMonth INT);
INSERT INTO months VALUES(201201);
INSERT INTO months VALUES(201202);
INSERT INTO months VALUES(201203);
....

SELECT m.yearMonth, COUNT(*) 
FROM 
    months m, users u
WHERE
    m.yearMonth >= CONVERT(INT, 
                        CONVERT(VARCHAR(4), DATEPART(yy, date_start) + 
                        CONVERT(VARCHAR(2), DATEPART(mm, date_start)
                      )
AND m.yearMonth <= CONVERT(INT, 
                        CONVERT(VARCHAR(4), DATEPART(yy, date_end) + 
                        CONVERT(VARCHAR(2), DATEPART(mm, date_end)
                      )

Note: This is SQL Server but you should be able to get the MySQL counterpart for CONVERT/DATEPART functions, I guess.

OTHER TIPS

try something like that

    SELECT DATE_FORMAT(???, '%Y/%m') , userID 
     FROM users 
     WHERE ??? BETWEEN '2012/01' AND '2012/05' 
     GROUP BY DATE_FORMAT(???, '%Y%m');

u was right just dont use count(userID)

EDIT:

you are missing one column in your database . it should be last_active_date so when user login it will update this date of last_active_date and you know that he was active in that date.

in your sql now , you cant know that they are active or when they logged in? if you will have this column it will be like that in your sql

 WHERE last_active_date BETWEEN '2012/01' AND '2012/05' 

You may create table and trigger for this. where active_user is added you must increment value in table. on user exit decrement. after this step count of users will be a current value in table.

this way save your time( because "between" is not lite operation for big table(and if you dont have indexes on field date_start)).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top