查找间隔中的最大登录次数

时间:2013-10-30 22:29:33

标签: sql tsql sql-server-2012

我为人们提供了timestampsstates的表格。

|:--------------------------------------------------------------:|
| user_id   |  state | start_time          | end_time            |
|:--------------------------------------------------------------:|
| 4711      |  1     | 2013-10-30 09:01:23 | 2013-10-30 17:12:03 |
| 4712      |  1     | 2013-10-30 07:01:23 | 2013-10-30 18:12:03 |
| 4713      |  1     | 2013-10-30 08:01:23 | 2013-10-30 16:12:03 |
| 4714      |  1     | 2013-10-30 09:01:24 | 2013-10-30 17:02:03 |

我的挑战是,找出有多少用户 每个时间间隔同一时间MAX(logged on) AND AVG(logged on)。我认为,当我看到有多少用户每秒同时登录时,我就会离开。

|:-------------------------------------:|
| timestamp  |  state | userid          |
|:-------------------------------------:|
| 1383123683 |  1     | 4711            |
| 1383123684 |  1     | 4711            |
| 1383123684 |  1     | 4712            |
| 1383123685 |  1     | 4711            |
| 1383123685 |  1     | 4712            |
| ...        | ...    | ...             |

顺便说一下,一个时间间隔是四分之一小时。

数据来自INSERT INTO所以我的想法是创建一个触发器并在帮助表中写入每行一行(UNIX时间戳),在开始和结束之间添加state_id

最后,必须能够对秒进行分组并计算datasets以查明一秒钟内存在多少行。对于AVG我还没有公式:-)。你知道,这是一个时间问题。

但我不确定,如果我的想法很好,因为我担心我的计划需要大量的表现和空间。

更好的想法是,只写start-timeend-time,但我失去了分秒的可能性。

如果我的数据库中没有数千行,我该如何管理?

1 个答案:

答案 0 :(得分:0)

这里可以有几个解决方案,我想描述一个,我希望你可以使用/自适应/扩展它以满足你的特定需求(注意:我使用的是mysql方言,对于ms sql它可能有点不同语法,但方法将起作用):

1 创建新表格,其结构如下:

create table changelog (
changetime datetime,
changevalue int,
totalsum int,
primary key (changetime)
);

2 插入基本数据:

insert into changelog
select changet, sum(cnts), 0
from
(
select start_time as changet, 1 as cnts from testlog
union all
select end_time as changet, -1 from testlog
) as q
group by changet;

3 update totalsum colum:

update changelog as a set totalsum = ifnull((select sum(changevalue) from (select changet, sum(cnts) as changevalue, 0
from
(
select start_time as changet, 1 as cnts from testlog
union all
select end_time as changet, -1 from testlog
) as q
group by changet) as b where b.changet<=a.changetime),0);

注意:对于ms sql,您可以尝试with语法,您可以将这些插入/更新作为一个查询进行

4 之后您将(根据问题数据):

2013-10-30 07:01:23 1   1
2013-10-30 08:01:23 1   2
2013-10-30 09:01:23 1   3
2013-10-30 09:01:24 1   4
2013-10-30 16:12:03 -1  3
2013-10-30 17:02:03 -1  2
2013-10-30 17:12:03 -1  1
2013-10-30 18:12:03 -1  0

如您所见,max已登录此处,但这里有一个问题,想象您需要为范围选择数据:08:00-08:01,表中没有数据,所以这样的查询不会工作:

SELECT max(totalsum)
FROM changelog
where changetime between cast(@startrange as datetime) and cast(@endrange as datetime)

但您可以将其更改为:

SELECT max(totalsum)
from
(
select max(totalsum) as totalsum FROM changelog
where changetime between cast(@startrange as datetime) and cast(@endrange as datetime)
union all
select totalsum from changelog where changetime=(select max(changetime) from changelog where changetime<cast(@startrange as datetime))
) as q;

所以,基本上说 - 除了你的范围,你需要在句号开始之前获取最后一行,以找出在范围开始时有多少用户

5 现在,您想要计算平均值。平均值是一种棘手的功能,取决于您的理解 - 可能会有不同的结果,平均用户每秒或平均工作量

这是区别:

100 users logged in at 09:00
98 users logged out at 09:01
1 user logged out at 09:02
Selection range: 09:00 - 09:59 (inclusive)

每分钟平均值将是每分钟所有登录用户的总和除以60

(100 + 2 + 1 + 57*1)/60 = 2.6(6) user per minute

但平均工作量可以计算为(max(logged_users)+ min(logged_users))/ 2

(100 + 1)/2 = 50.5 users, this is average simultaneous users logged in system

可以通过SQL avg(sum(values)/ count(values))计算另一个平均值,这将给我们

(100+98+1)/3 = 66.3(3) - another average workload in persons

第一个公式告诉我们, 2.65用户在同一时间,但第二个显示“圣#*&amp;#@#@,同时是50.5个用户”

另一个例子:

100 users logged in at 09:00
99 users logged out at 09:58
1 user logged out at 09:59
Selection range: 09:00 - 09:59 (inclusive)

第一个公式将为您提供(100*58 + 2 + 1)/60 = 96.71(6)个用户,第二个公式将继续提供50.5,第三个公式仍为66.3(3)

什么样的平均值最适合你?

要计算第一个平均值,您需要创建stored procedure,这将获得每个分钟/秒的数据并在分割后对其进行汇总

要计算第二个变体:只需选择min/max并除以2

第三种变体:使用avg代替max

注意#1:当然所有这些方法都非常慢,流量很大,所以我建议您准备一些“预先计算”的表格,其中包含可以快速获取的数据(例如,您可以像每小时一样获取数据:YYYY-MM-DD HH loggedInatStart, min, avg, median, max, loggedInatEnd

注意#2:有时median average对于统计目的来说更有趣,为了获得它,您将:每分钟计算登录的用户数,选择不同的值,从此列表中选择中间(对于我的示例)这将给我们2和2),或选择所有值,选择中间值(对于我的例子,它将给我们1和99)