首先:对标题感到抱歉,但也许我以后会找到更好的。
几分钟前我问过这个问题,但由于我无法描述我想要的东西,所以我再试了一次:)
这是我的表结构: http://sqlfiddle.com/#!2/b25f9/37
该表用于存储用户 session 。
除此之外,我想生成一个堆叠条形图,显示我有多少活跃用户。我的想法是,我像这样根据用户最近几天的在线时间对用户进行分组
假设是星期五:
- B 组:周四(和今天)在线的用户
- C 组:星期四但星期三(和今天)不在线的用户
- D 组:周四或周三不在线但周二(和今天)在线的用户
- E 组:周四、周三或周二未在线但上周一、周日或周六(以及今天)的用户
A 组:与其他组不匹配(但仅在今天)的用户
我只想知道这些组中的用户数量(特定日期)
- 一个用户只能属于这些组之一(在同一天)
最佳答案
另一个更新:不小心(通过复制和粘贴)有 starttime = ... 或 starttime = ...
但它应该是 starttime = ... 或结束时间 = ...
更新:
更详细地解释我的查询(在最终查询中有更多评论):
首先我们得到了
SELECT
...
FROM gc_sessions s
WHERE DATE(starttime) = CURDATE() OR DATE(endtime) = CURDATE()
这无异于说“给我 session 今天开始或今天结束的所有用户”。不得不一次又一次地考虑这两次使得查询有点笨拙,但实际上并没有那么复杂。
所以,通常我们会使用 COUNT() 函数来计算某些东西,显然,但由于我们想要“条件计数”,我们只需使用 SUM() 函数并告诉它何时加 1 以及何时不加 1。
SUM (CASE WHEN ... THEN 1 ELSE 0 END) AS a_column_name
SUM() 函数现在检查今天 session 结果集中的每一行。因此,对于此结果集中的每个用户,我们都会查看该用户是否在我们指定的日期在线。他/她在线多少次并不重要,因此出于性能原因,我们使用 EXISTS
。使用 EXISTS
,您可以指定一个子查询,该子查询在找到某些内容后立即停止,因此只要它不是 NULL
,它返回什么并不重要。 .所以不要对我选择 1
的原因感到困惑。在子查询中,我们必须将当前从外部查询检查的用户与来自内部查询(子查询)的用户连接起来,并指定时间窗口。如果所有条件都满足计数 1,否则计数 0,如前所述。
SUM(CASE WHEN
EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) = CURDATE() - INTERVAL 1 DAY)
OR (date(endtime) = CURDATE() - INTERVAL 1 DAY)))
THEN 1 ELSE 0 END) AS todayAndYesterday,
然后我们为每个条件创建一列,瞧,您在一个查询中就拥有了所有需要的东西。因此,随着您更新的问题,您的标准发生了变化,我们只需要添加更多规则:
SELECT
/*this is like before*/
SUM(CASE WHEN
EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) = CURDATE() - INTERVAL 1 DAY)
OR (date(endtime) = CURDATE() - INTERVAL 1 DAY)))
THEN 1 ELSE 0 END) AS FridayAndThursday,
SUM(CASE WHEN
EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) = CURDATE() - INTERVAL 2 DAY)
OR (date(endtime) = CURDATE() - INTERVAL 2 DAY)))
/*this one here is a new addition, since you don't want to count the users that were online yesterday*/
AND NOT EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) = CURDATE() - INTERVAL 1 DAY)
OR (date(endtime) = CURDATE() - INTERVAL 1 DAY)))
THEN 1 ELSE 0 END) AS FridayAndWednesdayButNotThursday,
SUM(CASE WHEN
EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) = CURDATE() - INTERVAL 3 DAY) /* minus 3 days to get tuesday*/
OR (date(endtime) = CURDATE() - INTERVAL 3 DAY)))
/*this is the same as before, we check again that the user was not online between today and tuesday, but this time we really use BETWEEN for convenience*/
AND NOT EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) BETWEEN CURDATE() - INTERVAL 2 DAY AND CURDATE() - INTERVAL 1 DAY)
OR (date(endtime) BETWEEN CURDATE() - INTERVAL 2 DAY AND CURDATE() - INTERVAL 1 DAY)))
THEN 1 ELSE 0 END) AS FridayAndTuesdayButNotThursdayAndNotWednesday,
.../*and so on*/
FROM gc_sessions s
WHERE DATE(starttime) = CURDATE() OR DATE(endtime) = CURDATE()
那么,我希望你现在明白了。还有问题吗?随意问。
更新结束
上一版问题的答案:
select
SUM(CASE WHEN EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) = CURDATE() - INTERVAL 1 DAY)
OR (date(starttime) = CURDATE() - INTERVAL 1 DAY)))
THEN 1 ELSE 0 END) AS todayAndYesterday,
SUM(CASE WHEN EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) BETWEEN CURDATE() - INTERVAL 2 DAY AND CURDATE() - INTERVAL 1 DAY)
OR (date(starttime) BETWEEN CURDATE() - INTERVAL 2 DAY AND CURDATE() - INTERVAL 1 DAY)))
THEN 1 ELSE 0 END) AS todayAndYesterdayOrTheDayBeforeYesterday,
SUM(CASE WHEN EXISTS (SELECT 1 FROM gc_sessions sub_s WHERE s.user = sub_s.user
AND ((date(starttime) BETWEEN CURDATE() - INTERVAL 7 DAY AND CURDATE() - INTERVAL 1 DAY)
OR (date(starttime) BETWEEN CURDATE() - INTERVAL 7 DAY AND CURDATE() - INTERVAL 1 DAY)))
THEN 1 ELSE 0 END) AS todayAndWithinTheLastWeek
from gc_sessions s
where date(starttime) = CURDATE()
or date(endtime) = CURDATE()
关于mysql - 这可以用mysql吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14561430/