MySQL每月活跃用户数

时间:2017-05-15 10:25:17

标签: mysql

有人可以帮助我为活跃用户创建一个mysql月度报告。 用户在特定日期拜访医生。该日期记录在访问日期。然后他们会立即预约他们应该回来的约会日期。用户活跃的月份是从访问月份到预约日期月份加上90天宽限期的用户。如果他们不在约会日期,他们将获得90天的宽限期,其中他们'仍然会被视为活跃用户。之后他们不再被认为是活跃的。

Users Table
+------------+------------+------------+
|  UserID    |  visit     |Appointment |  
+------------+------------+------------+
| 10001      | 01-01-2010 | 01-02-2010 | 
| 10001      | 05-02-2010 | 01-03-2010 | 
| 10002      | 20-07-2010 | 15-10-2010 | 
| 10003      | 01-11-2010 | 10-11-2010| 
+------------+------------+------------+

期望的结果将是

Monthly Report
+------------+------------+------------+
|  Month     |  active    |            |  
+------------+------------+------------+
| 2010-01    | 1          |            | 
| 2010-02    | 1          |            | 
| 2010-03    | 1          |            | 
| 2010-04    | 1          |            | 
| 2010-05    | 1          |            | 
| 2010-07    | 1          |            |
| 2010-08    | 1          |            | 
| 2010-09    | 1          |            | 
| 2010-10    | 1          |            | 
| 2010-11    | 2          |            | 
| 2010-12    | 2          |            | 
| 2011-01    | 1          |            | 
+------------+------------+------------+

这是sql代码

  CREATE TABLE `visits` (
   `id` int(10) NOT NULL,
   `userid` int(10) NOT NULL,
   `visit` date NOT NULL,
   `appointment` date NOT NULL
   ) ENGINE=InnoDB DEFAULT CHARSET=latin1;



INSERT INTO `visits` (`id`, `userid`, `visit`, `appointment`) VALUES
(1, 10001, '2010-01-01', '2010-02-01'),
(2, 10001, '2010-02-05', '2010-03-01'),
(3, 10002, '2010-07-20', '2010-10-15'),
(4, 10003, '2010-11-01', '2010-11-10');


ALTER TABLE `visits`
ADD PRIMARY KEY (`id`);

ALTER TABLE `visits`
  MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10007;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

2 个答案:

答案 0 :(得分:1)

对于那些可能需要这个的人。

SELECT
date_format(c.dt,'%Y-%m') AS "month",
c.dt AS date,
a.visit,
a.fu,
COUNT(DISTINCT userid) AS Active
FROM calendar_table c
LEFT JOIN visits v ON c.dt BETWEEN date_format(v.visit,'%Y-%m') AND 
DATE_SUB(date_add(v.appointment, INTERVAL 90 day), INTERVAL 
date_format((LAST_DAY(date_add(v.appointment, INTERVAL 90 day))),'%d')-1 DAY)
WHERE c.d = 1
AND c.y IN (2010,2011)
GROUP BY c.dt

答案 1 :(得分:0)

这种类型的要求通常需要某种形式的"计数表"和/或"日历表"。也就是说,对于你的专栏" month",你真的需要这是一个表格。这使您可以将日期范围表示为一组行(在这种情况下每月一个)。

如果您将日期范围表示为行,则在连接条件中使用“visits之间的外部联接”。这将允许您计算每个时间单位有多少用户。

对于以下示例,我使用了this article on a calendar table

中的代码
CREATE TABLE calendar_table (
    dt DATE NOT NULL PRIMARY KEY,
    y SMALLINT NULL,
    q tinyint NULL,
    m tinyint NULL,
    d tinyint NULL,
    dw tinyint NULL,
    monthName VARCHAR(9) NULL,
    dayName VARCHAR(9) NULL,
    w tinyint NULL,
    isWeekday BINARY(1) NULL,
    isHoliday BINARY(1) NULL,
    holidayDescr VARCHAR(32) NULL,
    isPayday BINARY(1) NULL
);

CREATE TABLE ints ( i tinyint );

INSERT INTO ints VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);

INSERT INTO calendar_table (dt)
SELECT DATE('2010-01-01') + INTERVAL a.i*10000 + b.i*1000 + c.i*100 + d.i*10 + e.i DAY
FROM ints a JOIN ints b JOIN ints c JOIN ints d JOIN ints e
WHERE (a.i*10000 + b.i*1000 + c.i*100 + d.i*10 + e.i) <= 11322
ORDER BY 1;

UPDATE calendar_table
SET isWeekday = CASE WHEN dayofweek(dt) IN (1,7) THEN 0 ELSE 1 END,
    isHoliday = 0,
    isPayday = 0,
    y = YEAR(dt),
    q = quarter(dt),
    m = MONTH(dt),
    d = dayofmonth(dt),
    dw = dayofweek(dt),
    monthname = monthname(dt),
    dayname = dayname(dt),
    w = week(dt),
    holidayDescr = '';

现在,根据您的问题使用您的示例数据,使用以下查询:

select
      date_format(c.dt,'%Y-%m') as "month"
    , count(distinct userid) as active
from calendar_table c
left join visits v on c.dt between v.visit and date_add(v.appointment, INTERVAL 90 DAY)
where c.y in (2010,2011)
group by
      date_format(c.dt,'%Y-%m')

请注意,此方法将为您提供24行(每月超过2年),因此您将获得更多的零行,而不是问题的预期结果。只需调整where子句以适合所需的日期范围。

请参阅此operating as an example at sqlfiddle

注意:此示例中没有注意索引或性能