在时间段之后或基于辅助列计算重复出现次数

时间:2013-06-01 13:40:22

标签: sql sql-server sql-server-2012

我目前有一个访问日志表,如下所示

LogID  UserID  BuildingID  Date/Time
===========================================
1      1       1           2013-01-01 10:00
2      2       1           2013-01-01 10:00
3      3       1           2013-01-01 10:30
4      3       2           2013-01-01 11:00
5      2       1           2013-01-01 11:00
6      4       1           2013-01-01 11:30
7      5       1           2013-01-01 11:30
8      5       1           2013-01-01 11:31
9      1       3           2013-01-01 12:00
10     1       3           2013-01-01 12:03
11     1       2           2013-01-01 12:05

我需要做的是创建一个查询,根据以下两个条件计算重复用户记录的数量:

  1. 大于X分钟的时差 - X将是用户指定的参数
  2. 用户的每个不同建筑
  3. 例如,如果我将时差设置为5分钟,那么我的结果将是:

    UserID   AccessCount
    ====================
    1        3            <-- +1 for timediff (ID 1,10) +1 for building (ID 11)
    2        2            <-- +1 for timediff (ID 2,5)
    3        2            <-- +1 for building (ID 3,4)
    4        1
    5        1            <-- duplicate ignored because DateDiff < 5min
    

    希望这是有道理的。

    为了给出一些背景知识,这是为了对我们的一些建筑物进行滑动访问,并且对于某些分析性安全报告,业务要求也随之降低。基本上我们希望在给定时间段内检查重复访问(通常在周末完成),但需要考虑到某些滑动点失败并需要用户多次滑动的事实。这就是为什么我希望dateiff作为滑动错误通常意味着用户会在很短的时间内多次滑动。

    非常感谢任何帮助,提前谢谢!

2 个答案:

答案 0 :(得分:3)

您可以通过考虑计算行数而不计算行来重新定义逻辑。当它位于同一建筑物上并且在同一建筑物的前一个日期时间的某个时间段内时,您不计算一行。

我认为这可能是你想要的:

select userId, count(*)
from (select LogID, UserID, BuildingID, dt,
             lag(dt) over (partition by userid, buildingid) as prevdt
      from t
     ) t
where dt > prevdt + TIMEDIFF or prevdt is NULL

在SQL中,添加到日期时间的常量被解释为天数。所以,5分钟将是(5.0/60)/24

您的数据中没有示例,但如果您有三行:

1   1   1   11:30
2   1   2   11:31
3   1   1   11:32

然后这不计算第三行,因为第一行覆盖第1行。

答案 1 :(得分:0)

这是一种方法:

declare @duplicateMinutes int = 5

select UserID, AccessCount = count(1)
from AccessLogs a
where not exists
  (
    select 1
    from AccessLogs d
    where a.LogID < d.LogID -- add this to try and avoid duplicate times cancelling each other
      and a.UserID = d.UserID
      and a.BuildingID = d.BuildingID
      and a.SwipeTime >= dateadd(mi, -@duplicateMinutes, d.SwipeTime)
      and a.SwipeTime <= d.SwipeTime
  )
group by UserID
order by UserID

SQL Fiddle with demo - 为您的数据提供预期结果。