1

首先:对不起标题,但也许我以后会找到更好的。

几分钟前我问过这个问题,但由于我无法描述我想要什么,我再试一次:)

这是我的表结构: http ://sqlfiddle.com/#!2/b25f9/37

该表用于存储用户会话。

为此,我想生成一个堆积条形图,显示我有多少活跃用户。我的想法是像这样根据用户最近几天的在线时间对用户进行分组 在此处输入图像描述

让我们说它的星期五:

  • B 组:周四(和今天)在线的用户
  • C组:星期四(和今天)不在线的用户
  • D组:周四或周三不在线但周二(和今天)的用户
  • E组:周四、周三或周二不在线但上周一、周日或周六(以及今天)的用户
  • A 组:与其他组不匹配的用户(但仅在今天)

  • 我只想知道这些组中的用户数量(特定日期)

  • 用户只能在其中一个组中(同一天)
4

6 回答 6

2

另一个更新:意外(通过复制和粘贴)starttime = ... or starttime = ...但应该是starttime = ... or endtime = ...

更新:

为了更详细地解释我的查询(在最终查询中还有更多评论):

首先我们得到了

SELECT
...
FROM gc_sessions s
WHERE DATE(starttime) = CURDATE() OR DATE(endtime) = CURDATE()

这无异于说“给我今天开始或今天结束会话的所有用户”。不得不一次又一次地考虑这两次使查询有点笨拙,但实际上并没有那么复杂。

因此,通常我们会使用 COUNT() 函数来计算某些东西,但由于我们想要“条件计数”,我们只需使用 SUM() 函数并告诉它何时加 1,何时不加 1。

SUM (CASE WHEN ... THEN 1 ELSE 0 END) AS a_column_name

SUM() 函数现在检查从今天开始的会话结果集中的每一行。因此,对于此结果集中的每个用户,我们都会查看该用户是否在我们指定的日期在线。他/她在线多少次并不重要,因此出于性能原因,我们使用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()
于 2013-01-28T12:21:02.517 回答
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;
于 2013-01-28T12:31:21.507 回答
1

我建议您不要依赖会话表,而是创建单独的表,其中存储 2 个字段,日期和 user_id。每次用户登录时,您都需要在此表中插入新条目。

这样,您将能够检索您的所有 3 个要求。

于 2013-01-28T12:00:56.653 回答
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)

where@range保存有关天数的信息。请参阅您的扩展 sql fiddle - http://sqlfiddle.com/#!2/9584b/24

于 2013-01-28T12:20:14.793 回答
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);
于 2013-01-28T12:01:32.330 回答
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;
于 2013-01-28T12:35:31.007 回答