total user count monthwise

Go To StackoverFlow.com

2

mySQL total user count

Grouping by month

I want to list the total count of registered users grouped by month

Well, the difficulty about this is that I don't want the count per month, but the the total count of users up to (and including) the month.

User table structure

+---------------+--------------+------+-------------------+----------------+
| Field         | Type         | Null | Default           | Extra          |
+---------------+--------------+------+-------------------+----------------+
| ID            | int(11)      | NO   | NULL              | auto_increment |
| email         | varchar(225) | NO   | NULL              |                |
................................-CUT-.......................................
| registered    | timestamp    | NO   | CURRENT_TIMESTAMP |                |
+---------------+--------------+------+-------------------+----------------+

Example data

1 example1@mail 2012-04-04 xx:xx:xx
2 example2@mail 2012-05-04 xx:xx:xx
3 example3@mail 2012-05-04 xx:xx:xx

Preferred output

+------+-------+-------+
| Year | Month | Count |
+------+-------+-------+
| 2012 | 01    | 0     |
| 2012 | 02    | 0     |
| 2012 | 03    | 0     |
| 2012 | 04    | 1     |
| 2012 | 05    | 3     |
+------+-------+-------+

The NULL results aren't necessary.

How could I achieve that result in pure mySQL?

2012-04-04 17:05
by noneevr2
I've tried several queries with COUNT(*) and GROUP BY YEAR(registered), MONTH(registered) . I made a join experiment too, but I'm not yet on an advanced level of mySQL - noneevr2 2012-04-04 17:27


3

I have not tried this but something along these lines should work -

SELECT tots.*, @var := @var + tots.`count`
FROM (
    SELECT
        YEAR(registered) AS `year`,
        MONTH(registered) AS `month`,
        COUNT(*) AS `count`
    FROM user
    GROUP BY `year`, `month`
) AS tots, (SELECT @var := 0) AS inc
2012-04-04 17:35
by nnichols
Using the updated query, works AWESOME thanks a lo - noneevr2 2012-04-04 17:45
Try my updated quer - nnichols 2012-04-04 17:45
Around here we say thanks by accepting answers and upvoting. Just click on the tick next to the answer you want to accept - nnichols 2012-04-04 17:53
Of course, I just wanted to comment the other's answers. I can't up-vote yet since my rep is too low - noneevr2 2012-04-04 17:58
Sorry, didn't mean to pressure you. Quite often new users on here disappear not to be seen until their next problem arises - nnichols 2012-04-04 18:02


0

This approach first gets the first day of the month for all months in which any registration occurred. It then joins to every user that had a registration greater than the first day of the month, and then counts the number of users.

SELECT
    YEAR(dates.first_day_of_month) AS registration_year,
    MONTH(dates.first_day_of_month) AS registration_month,
    COUNT(u.ID)
FROM (
    SELECT DISTINCT
        DATE_SUB(
            DATE_ADD(
                DATE_SUB(registered,INTERVAL (DAY(registered)-1) DAY), 
            INTERVAL 1 MONTH), 
        INTERVAL 1 SECOND) first_day_of_month
    FROM user 
) dates 
    LEFT JOIN user u ON u.registered <= dates.first_day_of_month
GROUP BY dates.first_day_of_month

If you want to avoid the gaps in months where no registrations occurred, you could substitute the sub-query with another that used a pre-existing "numbers" table to get a list of all possible months.

2012-04-04 17:41
by Michael Fredrickson
Thanks for your help. I'll use @nnichols method, he was first. However, notice that your code contains a small bug, The totals are calculated "upside down" (2011 - total of 2, 2012 - total of 1 - noneevr2 2012-04-04 17:53
@noneevr2 You're right, thanks... the >= should have been <=Michael Fredrickson 2012-04-04 17:58
Now it works flawlessl - noneevr2 2012-04-04 18:02
I think you need to change the calculation to get the last second of the month - nnichols 2012-04-04 18:22
@nnichols You're right... boy, fixing that made my query a lot uglier... +1 for your much cleaner answer - Michael Fredrickson 2012-04-04 18:30
Not really any better but you could use - LAST_DAY(registered) + INTERVAL 1 DAY - INTERVAL 1 SECONDnnichols 2012-04-04 18:33


0

You can do it with a couple of user variables:

set @c = 0;
set @d = 0;
select y, m, @d := @d + Count as Count from
  (select year(registered) as y, 
     month(registered) as m, 
     @c := @c + count(*) as Count
   from user
   group by y,m) as t;

gives you

+------+------+-------+
| y    | m    | Count |
+------+------+-------+
| 2011 |    1 |  2455 | 
| 2011 |    2 | 14253 | 
| 2011 |    3 | 42311 | 
2012-04-04 17:44
by D Mac
Your version works aswell, thanks. Please remove the "=" mark on line 3 right after the first at-d, it's causing a syntax error - noneevr2 2012-04-04 17:56
The syntax is correct for "@d := @d + Count..." - when you are in a select, that is how you assign a value to a user variable. What is the syntax error exactly? It must be from something else - D Mac 2012-04-04 23:29
Ads