我有一个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分钟 - 我正在寻找一种方法在几秒钟内完成。
答案 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总和中添加了一个来调整它。
答案 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