我有一个包含用户会话的表,即用户在我的应用程序上登录的时间段。每个会话都有一个开始和结束时间戳。
我可以通过一个查询确定当天每小时有多少用户在线(即有多少会话startTime <= hour AND endTime > hour
)?
我想显示过去2个月的平均值,但如果不可能,我可以使用1天的查询进行管理并计算脚本中的平均值。
示例结果:
Hour Online
00:00 10
01:00 12
02:00 10
....
16:00 100
17:00 120
....
(小时也可以是一个简单的整数,并不重要)
数据库是MySQL 5.
答案 0 :(得分:1)
我正在等待其他人介入,因为我不熟悉mysql,我相信必须有更好的解决方案。
这里的主要问题是构建一天中的小时表的方法。在mysql中没有递归选择能力迫使我通过union创建一个表。如果我们可以接受在该日期没有人登录的失踪日期,日期会更容易。如果没有,可以使用与小时类似的技巧来延长日期,例如七天。 交叉加入将生成一个日期表,每个日期都包含24小时。现在我们需要计算此时活跃的会话。为此,我们需要将startTime截断为小时边界,并将截断的startTime和endTime(不需要截断)放在交叉连接组合时间内。我们的数据终于来了。
要获得过去两个月的平均值,只需将此选项包装在另一个分组小时并计算平均值(用户)。如果您确实必须使用单个查询来返回两个数据集,则可以将此查询与平均查询结合使用,其中平均查询将为日期返回null。
附加免责声明:如前所述,我不知道MySql。我尝试使用在线手册编写日期和时间转换功能。可能失败了,但我相信你会纠正我。我也不确定保留关键字。
select days.date,
hour,
count (s.startTime) Users
from
(
(
select 0 hour
union
select 1 hour
union
select 2 hour
union
select 3 hour
union
select 4 hour
union
select 5 hour
union
select 6 hour
union
select 7 hour
union
select 8 hour
union
select 9 hour
union
select 10 hour
union
select 11 hour
union
select 12 hour
union
select 13 hour
union
select 14 hour
union
select 15 hour
union
select 16 hour
union
select 17 hour
union
select 18 hour
union
select 19 hour
union
select 20 hour
union
select 21 hour
union
select 22 hour
union
select 23 hour
) hours
cross join
(
-- We need date portion only
select distinct date(startTime) date from s
union select distinct date(endTime) from s
) days
)
left join s
-- date+hour, hopefully
on date_add(date, interval hour HOUR)
-- startTime is truncated to hour, hopefully
between date_sub(s.startTime interval minutes(s.startTime) MINUTE)
and s.endTime
-- last two months
where days.date between date_sub (now() interval 2 MONTH) and now()
group by days.date, hour
order by 1, 2
答案 1 :(得分:0)
我无法让Nikola的查询工作,但使用其中的一些技术来创建此查询,这可以获得整个时段的每小时平均值,这已经足够了。
SELECT hour, AVG(dayHourCount) FROM
(
SELECT hour, day, dayHour, COUNT(*) AS dayHourCount FROM
(
SELECT hour, day, day + INTERVAL hour HOUR AS dayHour FROM
(
select 0 AS hour
union
select 1 AS hour
union
select 2 AS hour
union
select 3 AS hour
union
select 4 AS hour
union
select 5 AS hour
union
select 6 AS hour
union
select 7 AS hour
union
select 8 AS hour
union
select 9 AS hour
union
select 10 AS hour
union
select 11 AS hour
union
select 12 AS hour
union
select 13 AS hour
union
select 14 AS hour
union
select 15 AS hour
union
select 16 AS hour
union
select 17 AS hour
union
select 18 AS hour
union
select 19 AS hour
union
select 20 AS hour
union
select 21 AS hour
union
select 22 AS hour
union
select 23 AS hour
) AS hours
INNER JOIN (SELECT DISTINCT DATE(start) AS day FROM PlayerSession ds WHERE ds.start > NOW() - INTERVAL 1 MONTH) AS days
) AS dayHours
LEFT JOIN PlayerSession s ON (s.start < dayHour AND s.lastActivity > dayHour)
LEFT JOIN Player p ON (s.player_id = p.id)
GROUP BY dayHour
) AS perDayHour
GROUP BY hour