Sql 计数(*)按相似时间戳分组

Sql 计数(*)按相似时间戳分组,sql,sql-server,tsql,group-by,Sql,Sql Server,Tsql,Group By,我的表中有一些数据(tb1): 我试图根据datetime1、datetime2和位置查找事件数 这就是我的问题: select count(*), datetime1, datetime2, grp from tb1 group by datetime1, datetime2, grp 这里没有问题 在某种程度上,我想根据以下内容来计算: 当两个连续行(可通过lead函数实现)之间的datetime1差小于1秒且两个连续行之间的datetime2差小于1秒时,则grp 我可以使用le

我的表中有一些数据(
tb1
):

我试图根据datetime1、datetime2和位置查找事件数

这就是我的问题:

 select count(*), datetime1, datetime2, grp 
 from tb1
 group by datetime1, datetime2, grp
这里没有问题

在某种程度上,我想根据以下内容来计算:

当两个连续行(可通过lead函数实现)之间的datetime1差小于1秒且两个连续行之间的datetime2差小于1秒时,则grp

我可以使用lead来查找两个连续行之间的差异,但不确定如何在这里应用count函数来按时间对两个连续行之间的相似性进行分组

为了使这更简单,我正在寻找类似这样的东西:

如果


如果需要进一步澄清,请告诉我。

我生成了一些样本数据。检查这是否是你要找的。我在代码中添加了必要的注释。查询可以更简洁,但我想在每个步骤上尽可能多地解释:

declare @table table (PK int, datetime1 datetime, datetime2 datetime, grp int)
insert into @table values
(1, '2016-01-01 00:30:14.000', '2016-01-01 00:33:15.000', 1),
(2, '2016-01-01 00:30:10.232', '2016-01-01 00:33:10.000', 1),
(3, '2016-01-01 00:30:10.111', '2016-01-01 00:33:10.234', 1),
(4, '2016-01-01 00:30:12.000', '2016-01-01 00:33:15.000', 2),
(5, '2016-01-01 00:30:10.000', '2016-01-01 00:33:10.234', 2),
(6, '2016-01-01 00:30:10.222', '2016-01-01 00:33:10.000', 2)

select min(pk), min(datetime1), count(*) from (
    --in this query, based on differences, we will generate grouping column called IsClose
    select *, case when (diff1 <= 1000 and diff2 <= 1000) or (diff3 <= 1000 and diff4 <= 1000) then 1 else 0 end [IsClose] from (
        --this query gives to additionals columns with absolute differences between consecutive rows ordered by PK column
        select *,
               abs(datediff(ms, datetime1, lag(datetime1) over (order by pk))) [diff1],
               abs(datediff(ms, datetime2, lag(datetime2) over (order by pk))) [diff2],
               abs(datediff(ms, datetime1, lead(datetime1) over (order by pk))) [diff3],
               abs(datediff(ms, datetime2, lead(datetime2) over (order by pk))) [diff4]  
        from @table
    ) [a]
) [a] group by grp, IsClose
declare@table表(PK int,datetime1 datetime,datetime2 datetime,grp int)
插入到@table值中
(1, '2016-01-01 00:30:14.000', '2016-01-01 00:33:15.000', 1),
(2, '2016-01-01 00:30:10.232', '2016-01-01 00:33:10.000', 1),
(3, '2016-01-01 00:30:10.111', '2016-01-01 00:33:10.234', 1),
(4, '2016-01-01 00:30:12.000', '2016-01-01 00:33:15.000', 2),
(5, '2016-01-01 00:30:10.000', '2016-01-01 00:33:10.234', 2),
(6, '2016-01-01 00:30:10.222', '2016-01-01 00:33:10.000', 2)
从中选择最小值(主键)、最小值(日期时间1)、计数(*)(
--在这个查询中,基于差异,我们将生成名为IsClose的分组列

选择*,case when(diff1我生成了一些示例数据。检查这是否是您要查找的。我在代码中添加了必要的注释。查询可以更简洁,但我想在每个步骤上尽可能多地解释:

declare @table table (PK int, datetime1 datetime, datetime2 datetime, grp int)
insert into @table values
(1, '2016-01-01 00:30:14.000', '2016-01-01 00:33:15.000', 1),
(2, '2016-01-01 00:30:10.232', '2016-01-01 00:33:10.000', 1),
(3, '2016-01-01 00:30:10.111', '2016-01-01 00:33:10.234', 1),
(4, '2016-01-01 00:30:12.000', '2016-01-01 00:33:15.000', 2),
(5, '2016-01-01 00:30:10.000', '2016-01-01 00:33:10.234', 2),
(6, '2016-01-01 00:30:10.222', '2016-01-01 00:33:10.000', 2)

select min(pk), min(datetime1), count(*) from (
    --in this query, based on differences, we will generate grouping column called IsClose
    select *, case when (diff1 <= 1000 and diff2 <= 1000) or (diff3 <= 1000 and diff4 <= 1000) then 1 else 0 end [IsClose] from (
        --this query gives to additionals columns with absolute differences between consecutive rows ordered by PK column
        select *,
               abs(datediff(ms, datetime1, lag(datetime1) over (order by pk))) [diff1],
               abs(datediff(ms, datetime2, lag(datetime2) over (order by pk))) [diff2],
               abs(datediff(ms, datetime1, lead(datetime1) over (order by pk))) [diff3],
               abs(datediff(ms, datetime2, lead(datetime2) over (order by pk))) [diff4]  
        from @table
    ) [a]
) [a] group by grp, IsClose
declare@table表(PK int,datetime1 datetime,datetime2 datetime,grp int)
插入到@table值中
(1, '2016-01-01 00:30:14.000', '2016-01-01 00:33:15.000', 1),
(2, '2016-01-01 00:30:10.232', '2016-01-01 00:33:10.000', 1),
(3, '2016-01-01 00:30:10.111', '2016-01-01 00:33:10.234', 1),
(4, '2016-01-01 00:30:12.000', '2016-01-01 00:33:15.000', 2),
(5, '2016-01-01 00:30:10.000', '2016-01-01 00:33:10.234', 2),
(6, '2016-01-01 00:30:10.222', '2016-01-01 00:33:10.000', 2)
从中选择最小值(主键)、最小值(日期时间1)、计数(*)(
--在这个查询中,基于差异,我们将生成名为IsClose的分组列

选择*,case when(diff1这是基于int的,但同样的方法也适用于datetime

declare @T table (pk int identity primary key, val int);
insert into @T values ('1'), ('9'), ('9'), ('11'), ('2'), ('2'), ('3'), ('5'), ('7'), ('8');
select tt.pk, tt.val 
     , sum(ll) over (order by val, pk) as grp
from  ( select * 
             , case when lag(val,1) over (order by val, pk) is null 
                      or val - lag(val,1) over (order by val, pk) <= 1 then 0 
                    else 1 
               end as ll
          from @T t
      ) tt
order by val, pk;

pk          val         grp
----------- ----------- -----------
1           1           0
5           2           0
6           2           0
7           3           0
8           5           1
9           7           2
10          8           2
2           9           2
3           9           2
4           11          3
declare@T表(pk int identity主键,val int);
插入@T值('1')、('9')、('9')、('11')、('2')、('2')、('3')、('5')、('7')、('8');
选择tt.pk,tt.val
,合计(ll)超过(按val、pk订购)为grp
从(选择*
,滞后(val,1)超过(按val排序,主键)为空时的情况

或者val-lag(val,1)over(order by val,pk)这是基于int的,但同样的方法也适用于datetime

declare @T table (pk int identity primary key, val int);
insert into @T values ('1'), ('9'), ('9'), ('11'), ('2'), ('2'), ('3'), ('5'), ('7'), ('8');
select tt.pk, tt.val 
     , sum(ll) over (order by val, pk) as grp
from  ( select * 
             , case when lag(val,1) over (order by val, pk) is null 
                      or val - lag(val,1) over (order by val, pk) <= 1 then 0 
                    else 1 
               end as ll
          from @T t
      ) tt
order by val, pk;

pk          val         grp
----------- ----------- -----------
1           1           0
5           2           0
6           2           0
7           3           0
8           5           1
9           7           2
10          8           2
2           9           2
3           9           2
4           11          3
declare@T表(pk int identity主键,val int);
插入@T值('1')、('9')、('9')、('11')、('2')、('2')、('3')、('5')、('7')、('8');
选择tt.pk,tt.val
,合计(ll)超过(按val、pk订购)为grp
从(选择*
,滞后(val,1)超过(按val排序,主键)为空时的情况

或val-lag(val,1)over(order by val,pk)当两个连续行之间的datetime1差小于1秒且两个连续行之间的datetime2差小于1秒时,是否存在和缺少“已更正,thx,以及where和group by的顺序错误:)旁注:您一直在写这个短语“两个连续行”-但在关系数据库中,表的行本质上是未排序的,因此没有“连续行”这样的东西"。我知道这一点。我是通过使用lead函数查找后续行来实现这一点的,并在问题中补充说,thxImagine第2行可以与第1行或第3行分组。如何避免重复计数?当两个连续行之间的datetime1差小于1秒且datetime2差为b时,是否存在“和”缺失在两个连续的行之间,thx,where和groupby的顺序错误:)旁注:您一直在写短语“两个连续的行”-但在关系数据库中,表的行本质上是未排序的,因此不存在“连续的行”这类事情。我知道这一点。我是通过使用lead函数来找到后续行来实现这一点的,并在问题中补充说,thxImagine第2行可以与第1行或第3行分组,如何避免重复计算?谢谢@michałturczyn,非常好的主意,我应用了这一点,并提出了这一点,我无法理解您为什么同时使用lead和lag。Second、 为什么在最内部的查询中使用PK?它应该按datetime按lead order进行分区。在您的情况下,grp被忽略,只根据PK进行排序,这是错误的,因为查询可能会在下一行选择错误的内容。我确信这会给出错误的结果。再次感谢。因为它确实给了我idea@mohsenhs我很高兴能帮上忙:)谢谢@michałturczyn,非常好的主意,我应用了这个方法并得出了这个结论。我无法理解为什么在最内部的查询中同时使用前置和滞后。第二,为什么在最内部的查询中使用PK?它应该按前置顺序按日期时间进行划分。在您的情况下,grp被忽略,只根据PK进行排序,这是错误的,因为查询可能会在下一行选择错误的内容。我确信这是错误的结果。再次感谢。因为它确实给了我机会idea@mohsenhs我很高兴能帮上忙:)谢谢@Papazzo,val-lag这一行给了我这个想法。投票结果是。我把基于你和Michael的代码放在了Upvoted中。谢谢@Papazzo,val-lag这一行给了我这个想法。投票结果是。我把基于你和Michael的代码放在了Upvoted中