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
之后,您将始终至少有一个 TradeOnl
y。间隔在单个交易中始终是统一的。我想转置这些数据,使其看起来像这样:
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
我是 运行 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
之后,您将始终至少有一个 TradeOnl
y。间隔在单个交易中始终是统一的。我想转置这些数据,使其看起来像这样:
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