这可能与mysql有关吗?

时间:2013-01-28 11:51:46

标签: mysql

首先:抱歉标题,但也许我会在以后找到更好的标题。

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

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

该表用于存储用户会话。

除此之外,我想生成一个堆积条形图,该图表应显示我有多少活跃用户。我的想法是,我根据用户最近几天的在线时间对用户进行分组 enter image description here

让我们说周五:

  • B组:星期四(今天)在线的用户
  • C组:星期四但星期三(今天)不在线的用户
  • D组:星期四或星期三但星期二(今天)不在线的用户
  • E组:星期三,星期三或星期二但星期日,星期日或星期六(今天)不在线的用户
  • A组:与其他组不匹配的用户(但仅限今天)

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

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

6 个答案:

答案 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

查看扩展的sql小提琴

答案 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;