日期在N分钟内时的组记录

时间:2016-07-06 03:20:52

标签: sql sql-server group-by

它并不像创建N分钟长的时间间隔那么简单。一条记录可能是10:04,另一条记录是10:17,其中N是15。

也许用户功能可行,也许是CTE。它可能需要在同一源表上进行多次连接。

我正在寻找最优雅的#34;解。也许SQL中有一个功能,我不知道哪个让这很​​容易。

这是一个让答案更加一致的参考方案:

create table Comparisons (
  DateField DateTime NOT NULL,
  Amount int not null, -- default to 5
)

insert into Comparisons (DateField) values ('2000-01-01 10:04'),('2000-01-01 10:17'),
('2000-01-01 12:01'),('2000-01-01 11:54'),('2000-01-01 03:02'),('2000-01-01 03:05'),
('2000-01-01 05:02'),('2000-01-01 05:05'),('2000-01-01 05:19')

预期输出:

  • min:.. 10:04,max:.. 10:17,总和:10
  • min:.. 11:54,max:.. 12:01,总和:10
  • min:.. 03:02,max:.. 03:05,总和:10
  • min:.. 05:02,max:.. 05:19,总和:15 [可选]

最后一个输出是可选的,但如果一个优雅的解决方案具有副作用,那么它是可以接受的。如果一个优雅的解决方案无法实现可选的最后输出,那么它就不会成为交易破坏者。

3 个答案:

答案 0 :(得分:2)

我相信这会产生你想要的结果:

DECLARE @Comparisons TABLE (i DATETIME, amt INT NOT NULL DEFAULT(5));
INSERT @Comparisons (i) VALUES ('2016-01-01 10:04:00.000')
, ('2016-01-01 10:17:00.000')
, ('2016-01-01 10:25:00.000')
, ('2016-01-01 10:37:00.000')
, ('2016-01-01 10:44:00.000')
, ('2016-01-01 11:52:00.000')
, ('2016-01-01 11:59:00.000')
, ('2016-01-01 12:10:00.000')
, ('2016-01-01 12:22:00.000')
, ('2016-01-01 13:00:00.000')
, ('2016-01-01 09:00:00.000');

DECLARE @N INT = 15;

WITH T AS (
    SELECT i
         , amt
         , CASE WHEN DATEDIFF(MINUTE, previ, i) <= @N THEN 0 ELSE 1 END RN1
         , CASE WHEN DATEDIFF(MINUTE, i, nexti) > @N THEN 1 ELSE 0 END RN2
    FROM @Comparisons t
    OUTER APPLY (SELECT MAX(i) FROM @Comparisons WHERE i < t.i)x(previ)
    OUTER APPLY (SELECT MIN(i) FROM @Comparisons WHERE i > t.i)y(nexti)
    )
, T2 AS (
    SELECT CASE RN1 WHEN 1 THEN i ELSE (SELECT MAX(i) FROM T WHERE RN1 = 1 AND i < T1.i) END mintime
         , CASE WHEN RN2 = 1 THEN i ELSE ISNULL((SELECT MIN(i) FROM T WHERE RN2 = 1 AND i > T1.i), i) END maxtime
         , amt
    FROM T T1
    )
SELECT mintime, maxtime, sum(amt) total
FROM T2
GROUP BY mintime, maxtime
ORDER BY mintime;

它可能比它可能有点笨拙,但它基本上只是在@ N分钟链中分组任何东西。

答案 1 :(得分:1)

您希望根据至少&lt; N&gt;之间的间隙对记录进行分组。分钟。

在SQL Server 2012+中,您可以使用lag()来识别组的开始时间和累积总和来识别组:

select min(datefield), max(datefield), count(*) as num, sum(amount)
from (select c.*,
             sum(case when prev_datefield < dateadd(minute, -N, datefield)
                      then 1 else 0
                 end) over (order by datefield) as grp
      from (select c.*,
                   lag(datefield) over (order by datefield) as prev_datefield
            from Comparisons c
           ) c
      ) c
group by grp;

在早期版本中,您可以使用相关子查询或apply来获得相同的功能(尽管性能要差得多)。

答案 2 :(得分:0)

如果检查相邻间隔,则可以使用间隔。这需要将源表记录乘以3

的伪代码:

select *
from Comparisons C, {-1, 0, 1} M
group by (datediff(mi, C.DateField, 0) / N) + M

这种方法的问题是如何消除额外的结果。我怀疑这是一种愚蠢的方法,但其他人可能会看到它的价值。

更新:此方法不适用于第4预期输出[min:.. 05:02,max:.. 05:19,总和:15]