SQL 服务器 window 函数基于时间的数据

SQL Server window function time based data

我是 运行 SQL Server 2016,我有一组数据如下所示

Name    Time                    Type
CL1 2018-05-22 10:50:00 -04:00  SampleAndTrade
CL1 2018-05-22 11:00:00 -04:00  TradeOnly
CL1 2018-05-22 11:10:00 -04:00  TradeOnly
CL1 2018-05-22 11:20:00 -04:00  TradeOnly
CL1 2018-05-22 14:10:00 -04:00  SampleAndTrade
CL1 2018-05-22 14:20:00 -04:00  TradeOnly
CL1 2018-05-22 14:30:00 -04:00  TradeOnly
CL1 2018-05-22 14:40:00 -04:00  TradeOnly
CL1 2018-05-22 14:50:00 -04:00  TradeOnly
HO1 2018-05-22 10:50:00 -04:00  SampleAndTrade
HO1 2018-05-22 11:00:00 -04:00  TradeOnly
HO1 2018-05-22 11:10:00 -04:00  TradeOnly
HO1 2018-05-22 11:20:00 -04:00  TradeOnly
HO1 2018-05-22 14:10:00 -04:00  SampleAndTrade
HO1 2018-05-22 14:20:00 -04:00  TradeOnly
HO1 2018-05-22 14:30:00 -04:00  TradeOnly
HO1 2018-05-22 14:40:00 -04:00  TradeOnly
HO1 2018-05-22 14:50:00 -04:00  TradeOnly

一个交易周期以 SampleAndTrade 开始,以 TradeOnly 结束(在下一个 SampleAndTrade 之前)。在 SampleAndTrade 之后,您将始终至少有一个 TradeOnly。间隔在单个交易中始终是统一的。我想转置这些数据,使其看起来像这样:

Name    StartTime    EndTime   IntervalMin
CL1     10:50        11:20     10
CL1     14:10        14:50     10
HO1     10:50        11:20     10
HO1     14:10        14:50     10

我真的不知道如何正确划分数据以在交易周期内滚动。谁能告诉我如何实现这一点?

您只需对 'SampleAndTrade' 进行累加即可分配一个组。然后聚合:

select name, min(time), max(time)
from (select t.*,
             sum(case when type = 'SampleAndTrade' then 1 else 0 end) over (partition by name order by time) as grp
      from t
     ) t
group by name, grp;

我不确定 intervalmin 是如何计算的。也许:

datediff(minute, min(time), max(time)) / count(*)
SELECT
  Name,
  MIN(Time)   AS StartTime,
  MAX(Time)   AS EndTime,
  MIN(Diff)   AS IntervalMin
FROM
(
  SELECT
    *,
    SUM(CASE WHEN type = 'SampleAndTrade' THEN 1 END)
      OVER (PARTITION BY Name
                ORDER BY Time
           )
             AS GroupID,
    DATEDIFF(
      MINUTE,
      LAG(Time)
        OVER (PARTITION BY Name
                  ORDER BY Time
             ),
      Time
    )
      AS Diff
  FROM
    yourTable
)
  AS summary
GROUP BY
  Name,
  GroupID

您还可以对旧版本使用相关方法

with tt as (
 select *, 
       (select count(*) 
        from table 
        where Name = t.name and  [type] = 'SampleAndTrade' and time <= t.time
        ) as Seq
 from table t
)

select Name, min(time), max(time), 
       datediff(minute, min(time), max(time)) as IntervalMin
from tt
group by Name, Seq;

这应该会让你到达那里

declare @t table (Name varchar(20), tm datetime2, Type varchar(20));
insert into @t values 
('CL1', '2018-05-22 10:50:00 -04:00', 'SampleAndTrade'),
('CL1', '2018-05-22 11:00:00 -04:00', 'TradeOnly'),
('CL1', '2018-05-22 11:10:00 -04:00', 'TradeOnly'),
('CL1', '2018-05-22 11:20:00 -04:00', 'TradeOnly'),
('CL1', '2018-05-22 14:10:00 -04:00', 'SampleAndTrade'),
('CL1', '2018-05-22 14:20:00 -04:00', 'TradeOnly'),
('CL1', '2018-05-22 14:30:00 -04:00', 'TradeOnly'),
('CL1', '2018-05-22 14:40:00 -04:00', 'TradeOnly'),
('CL1', '2018-05-22 14:50:00 -04:00', 'TradeOnly'),
('HO1', '2018-05-22 10:50:00 -04:00', 'SampleAndTrade'),
('HO1', '2018-05-22 11:00:00 -04:00', 'TradeOnly'),
('HO1', '2018-05-22 11:10:00 -04:00', 'TradeOnly'),
('HO1', '2018-05-22 11:20:00 -04:00', 'TradeOnly'),
('HO1', '2018-05-22 14:10:00 -04:00', 'SampleAndTrade'),
('HO1', '2018-05-22 14:20:00 -04:00', 'TradeOnly'),
('HO1', '2018-05-22 14:30:00 -04:00', 'TradeOnly'),
('HO1', '2018-05-22 14:40:00 -04:00', 'TradeOnly'),
('HO1', '2018-05-22 14:50:00 -04:00', 'TradeOnly');
with cte as 
( select t1.* 
       , lead(type) over (partition by name order by tm) as nextType
  from @t t1 
)
select t1.Name, t1.tm, min(t2.tm) 
   --, t1.Type, t2.tm, t2.nextType
  from cte t1 
  join cte t2 
    on t1.Name = t2.Name 
   and t1.Type = 'SampleAndTrade' 
   and (t2.nextType = 'SampleAndTrade' or t2.nextType is null)
   and t2.tm > t1.tm
 group by t1.Name, t1.tm
 order by t1.name, t1.tm