计算特定日期之间的用户数

时间:2014-05-26 19:16:15

标签: mysql datetime count

我有一个用户表,当他们签名时和last_seen:

+--------+-----------+-----------+
| userid | signed_up | last_seen |
+--------+-----------+-----------+
|      1 | 1/1/14    | 1/3/14    |
|      2 | 1/1/14    | 1/5/14    |
|      3 | 1/3/14    | 1/5/14    |
|      4 | 1/6/14    | 1/7/14    |
+--------+-----------+-----------+

让我们假设每个用户每天都会在signed_up和last_seen之间访问该网站。我想计算每天有多少用户。我正在寻找的结果如下:

+--------+----------------+
|  date  | count_of_users |
+--------+----------------+
| 1/1/14 |              2 |
| 1/2/14 |              2 |
| 1/3/14 |              3 |
| 1/4/14 |              2 |
| 1/5/14 |              2 |
| 1/6/14 |              1 |
| 1/7/14 |              1 |
+--------+----------------+

只是为了澄清,这里是如何计算数字的(我不需要这张表,这只是一个例子)

+--------+----------------+-------+-------+-------+-------+
|  date  | count_of_users | user1 | user2 | user3 | user4 |
+--------+----------------+-------+-------+-------+-------+
| 1/1/14 |              2 |     1 |     1 |       |       |
| 1/2/14 |              2 |     1 |     1 |       |       |
| 1/3/14 |              3 |     1 |     1 |     1 |       |
| 1/4/14 |              2 |       |     1 |     1 |       |
| 1/5/14 |              2 |       |     1 |     1 |       |
| 1/6/14 |              1 |       |       |       |     1 |
| 1/7/14 |              1 |       |       |       |     1 |
+--------+----------------+-------+-------+-------+-------+ 

不确定这是否超出了在MySql中应该做的事情...感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

Create a date range table

mysql> CREATE TABLE IF NOT EXISTS calendar (date DATE NOT NULL PRIMARY KEY);
mysql> INSERT INTO calendar (SELECT calendar.date
    FROM (
        SELECT (SELECT MIN(signed_up) FROM users)
               + INTERVAL (a.val + (10 * b.val)) DAY
        as date
        FROM (select 0 as val 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)
        as a
        CROSS JOIN (select 0 as val 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)
        as b
    ) calendar
    WHERE calendar.date BETWEEN
          (SELECT MIN(signed_up) FROM users) AND
          (SELECT MAX(last_seen) FROM users));  

mysql> select * from calendar;
+------------+
| date       |
+------------+
| 2014-01-01 |
| 2014-01-02 |
| 2014-01-03 |
| 2014-01-04 |
| 2014-01-05 |
| 2014-01-06 |
| 2014-01-07 |
+------------+
7 rows in set (0.00 sec)

mysql> select * from users;
+--------+------------+------------+
| userid | signed_up  | last_seen  |
+--------+------------+------------+
|      1 | 2014-01-01 | 2014-01-03 |
|      2 | 2014-01-01 | 2014-01-05 |
|      3 | 2014-01-03 | 2014-01-05 |
|      4 | 2014-01-06 | 2014-01-07 |
+--------+------------+------------+
4 rows in set (0.00 sec)

获得日期范围表后,您要查找的查询可以表示为JOIN / GROUP BY操作:

mysql> SELECT c.date, count(c.date)
       FROM calendar c JOIN users u WHERE c.date BETWEEN u.signed_up AND u.last_seen
       GROUP BY c.date;

+------------+---------------+
| date       | count(c.date) |
+------------+---------------+
| 2014-01-01 |             2 |
| 2014-01-02 |             2 |
| 2014-01-03 |             3 |
| 2014-01-04 |             2 |
| 2014-01-05 |             2 |
| 2014-01-06 |             1 |
| 2014-01-07 |             1 |
+------------+---------------+
7 rows in set (0.00 sec)

如果您经常进行此类查询,则需要生成(并保留)日历表。但是,如果您不想创建日历表,则可以使用单个查询动态生成结果:

mysql> SELECT c.date, COUNT(c.date)
FROM (SELECT calendar.date
     FROM (
         SELECT (SELECT MIN(signed_up) FROM users)
                + INTERVAL (a.val + (10 * b.val)) DAY
         as date
         FROM (select 0 as val 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)
         as a
         CROSS JOIN (select 0 as val 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)
         as b
     ) calendar
     WHERE calendar.date BETWEEN
           (SELECT MIN(signed_up) FROM users) AND
           (SELECT MAX(last_seen) FROM users)) c
JOIN users u WHERE c.date BETWEEN u.signed_up AND u.last_seen
GROUP BY c.date

产生

+------------+---------------+
| date       | COUNT(c.date) |
+------------+---------------+
| 2014-01-01 |             2 |
| 2014-01-02 |             2 |
| 2014-01-03 |             3 |
| 2014-01-04 |             2 |
| 2014-01-05 |             2 |
| 2014-01-06 |             1 |
| 2014-01-07 |             1 |
+------------+---------------+
7 rows in set (0.00 sec)

请注意,根据您需要的日历大小,您可能需要在CROSS JOINS语句中添加更多INSERT INTO calendar。有关示例,请参阅the link