首先:抱歉标题,但也许我会在以后找到更好的标题。
几分钟前我问过这个,但由于我无法描述我想要的东西,我再试一次:)
这是我的表格结构: http://sqlfiddle.com/#!2/b25f9/37
该表用于存储用户会话。
除此之外,我想生成一个堆积条形图,该图表应显示我有多少活跃用户。我的想法是,我根据用户最近几天的在线时间对用户进行分组
让我们说周五:
A组:与其他组不匹配的用户(但仅限今天)
我只想知道这些群组中的用户数量(特定日期)
答案 0 :(得分:2)
另一次更新:有意(通过复制和粘贴)有starttime = ... or starttime = ...
,但它应该是starttime = ... or endtime = ...
<强>更新强>
更详细地解释我的查询(在最终查询中还有更多评论):
首先我们得到了
SELECT
...
FROM gc_sessions s
WHERE DATE(starttime) = CURDATE() OR DATE(endtime) = CURDATE()
这就像是说“给我今天开会或今天结束的所有用户”。不得不一次又一次地考虑这两次使查询有点笨拙,但实际上并没有那么复杂。
所以,通常我们会使用COUNT()函数计算一些东西,显然,但是因为我们想要“条件计数”,我们只需使用SUM()函数并告诉它何时添加1和何时不添加。
SUM (CASE WHEN ... THEN 1 ELSE 0 END) AS a_column_name
SUM()函数现在检查从今天开始的会话结果集中的每一行。因此,对于此结果集中的每个用户,我们会查看此用户是否在线指定了我们指定的日期。他/她在线多少次并不重要,因此出于性能原因,我们使用EXISTS
。使用EXISTS
,您可以指定一个子查询,一旦找到某个内容就会停止,因此只要它不是NULL
,找到某些内容时它返回的内容并不重要。因此,不要混淆我选择1
的原因。在子查询中,我们必须将来自外部查询的当前检查的用户与来自内部查询(子查询)的用户连接,并指定时间窗口。如果所有的标准都满足计数1,那么就像之前解释过的那样。
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()
答案 1 :(得分:1)
我建议您创建单独的表,而不是依赖会话表,该表存储2个字段,date和user_id。 每次用户登录时,您都需要在此表中插入新条目。
通过这种方式,您将能够检索到您的所有3项要求。
答案 2 :(得分:1)
示例表:
CREATE TABLE `test`.`user_login_history` (
`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`userid` INTEGER UNSIGNED NOT NULL,
`date` DATETIME NOT NULL,
PRIMARY KEY (`id`)
)
ENGINE = InnoDB;
用户登录后,检查他/她是否已登录:
select count(*) from user_login_history where
userid = 1 and `date` = '2013-01-28 00:00:00';
如果返回值为1,表示他/她今天已登录。无需更改。
但是,如果返回值为0,表示他/她今天没有登录。所以记下来。
insert into user_login_history(userid,`date`)values(1,'2013-01-28 00:00:00');
Q1。今天有多少用户在线也是昨天在线?
select count(*) from user_login_history u where
u.`date` = '2013-01-28 00:00:00' and
(
select count(*) from user_login_history v where
v.`date` = '2013-01-27 00:00:00' and
v.userid = u.userid
) = 1;
Q2。今天在线有多少用户在最后两天内也在线
select count(*) from user_login_history u where
u.`date` = '2013-01-28 00:00:00' and
(
select count(*) from user_login_history v where
v.`date` >= '2013-01-26 00:00:00' and
v.`date` <= '2013-01-27 00:00:00' and
v.userid = u.userid
) > 0;
Q3。今天在线有多少用户在过去7天内也在线
select count(*) from user_login_history u where
u.`date` = '2013-01-28 00:00:00' and
(
select count(*) from user_login_history v where
v.`date` >= '2013-01-21 00:00:00' and
v.`date` <= '2013-01-27 00:00:00' and
v.userid = u.userid
) > 0;
答案 3 :(得分:0)
昨天
select id from gc_sessions where id in
(
select id
from gc_sessions
where starttime > subdate(current_date, 2)
and endtime < subdate(current_date, 1)
)
and starttime > subdate(current_date, 1);
2天
select id from gc_sessions where id in
(
select id
from gc_sessions
where starttime > subdate(current_date, 3)
and endtime < subdate(current_date, 1)
)
and starttime > subdate(current_date, 1);
连续7天
select id from gc_sessions where id in
(
select id
from gc_sessions
where starttime > subdate(current_date, 8)
and endtime < subdate(current_date, 1)
)
and starttime > subdate(current_date, 1);
答案 4 :(得分:0)
您需要添加一个子查询,用于加载指定范围内的数据(例如,1天/ 2天/ 7天),并将其与当天的数据进行比较。
set @range = 7;
select * from gc_sessions
WHERE user in (SELECT user from gc_sessions
where starttime between subdate(current_date, @range) AND subdate(current_date, 1))
AND starttime > subdate(current_date, 0)
@range
保存有关天数的信息。在 - http://sqlfiddle.com/#!2/9584b/24
答案 5 :(得分:0)
SELECT today.user
, GROUP_CONCAT(DISTINCT today.ip) ip
FROM gc_sessions today
JOIN gc_sessions yesterday
ON DATE(yesterday.starttime) = DATE(today.starttime) - INTERVAL 1 DAY
AND today.user = yesterday.user
WHERE DATE(today.starttime) = '2013-01-10'
GROUP
BY today.user;