使用进入和退出时间戳计算SQL中的运行计数(存储容量)

时间:2014-09-15 21:23:36

标签: sql sql-server

我有一个24小时的商店,我有一堆数据点用于客户进入和退出时间戳。我想知道在任何时候商店里有多少顾客。

我的数据如下:

CREATE TABLE Events (CustomerID INT, EventDTS DATETIME2, Delta INT);

Delta始终为1或-1,表示商店人口的变化。对于每个客户进入事件,最终都会有客户退出事件。

我想知道在任何给定时间点商店的占用情况。我不知道如何在SQL中有效地执行此操作(MS SQL Server 2012)。

这就是我想要的:

select * from EventsWithPopulation;
CustomerID |            EventDTS | Delta | Polulation
         1 | 2014-01-01 00:01:00 |     1 |          0
         2 | 2014-01-01 00:04:00 |     1 |          1
         3 | 2014-01-01 00:05:00 |     1 |          2
         1 | 2014-01-01 00:07:00 |    -1 |          3
         3 | 2014-01-01 00:07:00 |    -1 |          2
         2 | 2014-01-01 00:09:00 |    -1 |          1

我已经尝试创建游标来迭代数据并将delta应用于正在运行的计数变量,但这非常慢。它大约有300万行,计算事件的运行次数需要5分钟 - 我正在寻找一种方法在几秒钟内完成。

3 个答案:

答案 0 :(得分:2)

您正在使用SQL Server 2012,因此您可以使用累积总和。这简单易行:

select ewp.*,
       sum(Delta) over (order by EventDTS) as Population
from EventsWithPopulation ewp;

这将在任何事件发生后的瞬间为您提供人口。

编辑:

当有多个时间戳完全相同时,上面看起来有点奇怪。你可以通过放入一些东西来解决这个问题,使它们与众不同,可能是客户di:

select ewp.*,
       sum(Delta) over (order by EventDTS, CustomerId) as Population
from EventsWithPopulation ewp;

答案 1 :(得分:1)

戈登的回答将列出每个事件的人口。如果你想给它一个时间并获得人口,只需将午夜和现在之间的增量相加。

declare @mydate DateTime
set @mydate = GetDate()

Select 
  sum(delta) + 1
from
 EventsWithPopulation
where
  EventDTS between DateAdd(Day, Datediff(Day,0,@mydate), 0) and @mydate

编辑:因为输入事件不会立即反映在行中,而是反映在下一个事件中。三角洲总是落后于一个。我已经从delta总和中添加了一个来调整它。

Fiddle

答案 2 :(得分:1)

我认为窗口功能不会返回您想要的结果。我认为您需要使用相关子查询以及row_number

with cte as (
  select *, row_number() over (order by eventdts) rn
  from Events
  )
select *, 
  coalesce((select sum(delta)
   from cte e2
   where e2.rn < e.rn
   ),0) population
from cte e