我的数据库中有一个表,用于记录用户的时长 处于事件或非事件状态。如果用户从事件状态切换到非事件状态或 反之亦然(或更改任何其他属性,如地址等),则会添加新记录。简化版本如下所示:
UserID state state_from state_to
1 active 2016-12-14 2017-01-15
2 active 2016-12-14 2017-02-02
3 active 2017-01-01 NULL
1 inactive 2017-01-16 2017-03-05
2 inactive 2017-02-02 NULL
1 active 2017-03-06 NULL
我想计算每月有多少用户在某个时刻处于“活跃”状态。一月至三月所需的输出表为:
date user_count
2017-01 3
2017-02 2
2017-03 2
对于特定时间戳(例如 2017 年 1 月),我使用以下查询。
SET @stamp = '2017-01';
SELECT @stamp AS date, COUNT(UserID) AS user_count
FROM se_user
WHERE (state LIKE 'active' AND @stamp BETWEEN DATE_FORMAT(state_from,'%Y-%m') AND DATE_FORMAT(state_to,'%Y-%m') )
OR (state LIKE 'active' AND DATE_FORMAT(state_from,'%Y-%m') <= @stamp AND DATE_FORMAT(state_to,'%Y-%m') IS NULL);
我的问题是,我不知道如何在日期范围内执行此操作(例如从一月到三月)。有办法做到这一点吗?
示例数据库和表
-- Set up a test database
DROP DATABASE IF EXISTS se_toy_example;
CREATE DATABASE se_toy_example;
USE se_toy_example;
-- Create example table
DROP TABLE IF EXISTS se_user;
CREATE TABLE se_user (
UserID INT(10),
state VARCHAR(10),
state_from DATE,
state_to DATE
);
-- Populate table
INSERT INTO se_user (UserID,state,state_from,state_to)
VALUES (1,'active','2016-12-14','2017-01-15'),
(2,'active','2016-12-14','2017-02-02'),
(3,'active','2017-01-01',NULL),
(1,'inactive','2017-01-16','2017-03-05'),
(2,'inactive','2017-02-02',NULL),
(1,'active','2017-03-06',NULL);
最佳答案
您需要一个 calendar_table
来包含月份日期范围,并为每个月添加 dt_begin
和 dt_end
。
因此您对当前年份的查询变为。
<强> SQL DEMO
SELECT c.dt_begin, count(*)
FROM calendar_table c
JOIN se_user u
ON c.dt_begin <= COALESCE(u.state_to, curdate() )
AND c.dt_end >= u.state_from
WHERE dt_begin >= '2017-01-01'
AND dt_begin <= '2017-12-01'
AND state = 'active'
GROUP BY c.dt_begin
;
输出
注意:如果想要事件数为 0 的月份,可以使用LEFT JOIN
。
关于mysql - 统计MySQL中时间范围内的条目数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44142807/