查找状态字段与当前字段不同的下一条记录
Find next record where status field is different from current
我有一个 table 用于记录事件。具体有两种类型:ON 和 OFF。
有时会有重叠的日志条目,因为可以同时记录 2 个设备。这并不重要,因为最终报告应该 [大部分] 正确概述开启 -> 关闭期间。
下面是一个示例,第三列只是为了说明:它不存在。
ActionTaken ID ID_of_next_OFF
Switched ON 1 3
Switched ON 2 6
Switched OFF 3
Switched ON 4 7
Switched ON 5 8
Switched OFF 6
Switched OFF 7
Switched OFF 8
Switched On 9 10
Switched OFF 10
Switched On 11 12
Switched OFF 12
给定前两列,如何计算第三列?
这不起作用:
SELECT actionTaken, Id, LEAD(Id)
OVER (PARTITION BY ActionTaken ORDER BY ID) nextConn
FROM dbo.Events
因为它基于 ID_of_Next 下一个匹配的 actionTaken 值,而不是下一个替代值。
像这样的东西应该会让你到达那里。
下面我使用了 2 个 CTE 来拆分关闭和打开数据,然后为第一次打开第一次关闭提供了一个排名项,然后我使用联合查询来匹配它们
declare @Events table (
ActionTaken nvarchar(25),
ID int
);
insert @Events
values
--ActionTaken ID ID_of_next_OFF
('Switched ON' , 1), -- 3
('Switched ON' , 2),-- 6
('Switched OFF', 3),
('Switched ON' , 4),-- 7
('Switched ON' , 5),-- 8
('Switched OFF', 6),
('Switched OFF', 7),
('Switched OFF', 8),
('Switched On' , 9),-- 10
('Switched OFF', 10),
('Switched On' , 11),-- 12
('Switched OFF', 12);
with onrank as (
select row_number()over(order by id) ranking, * from @Events where ActionTaken like '%ON')
, offrank as (
select row_number()over(order by id) ranking, * from @Events where ActionTaken like '%OFF')
select o.ActionTaken, o.ID, case when o.ranking=f.ranking then cast(f.id as nvarchar(3)) end as Id_next_off
from onrank o inner join offrank f on o.ranking=f.ranking
union
select ActionTaken, ID, '' from offrank
order by o.ID;
你走对了。您只需要 'Switched ON'
部分的 LEFT JOIN
与 'Switched OFF'
部分在相同的行号上。
with Events as (
select 'Switched ON' as ActionTaken, 1 as ID union all -- 3
select 'Switched ON', 2 union all -- 6
select 'Switched OFF', 3 union all
select 'Switched ON', 4 union all -- 7
select 'Switched ON', 5 union all -- 8
select 'Switched OFF', 6 union all
select 'Switched OFF', 7 union all
select 'Switched OFF', 8 union all
select 'Switched On', 9 union all -- 10
select 'Switched OFF', 10 union all
select 'Switched On', 11 union all -- 12
select 'Switched OFF', 12
), E as (
select
*, row_number() over(partition by ActionTaken order by ID) as rn
from Events
)
select
a.ActionTaken, a.ID, b.ID
from E as a
left join E as b
on a.ActionTaken = 'Switched ON' and
b.ActionTaken = 'Switched OFF' and
a.rn = b.rn
order by a.ID, a.ActionTaken;
输出:
+--------------+----+------+
| ActionTaken | ID | ID |
+--------------+----+------+
| Switched ON | 1 | 3 |
| Switched ON | 2 | 6 |
| Switched OFF | 3 | NULL |
| Switched ON | 4 | 7 |
| Switched ON | 5 | 8 |
| Switched OFF | 6 | NULL |
| Switched OFF | 7 | NULL |
| Switched OFF | 8 | NULL |
| Switched On | 9 | 10 |
| Switched OFF | 10 | NULL |
| Switched On | 11 | 12 |
| Switched OFF | 12 | NULL |
+--------------+----+------+
使用 SQL Fiddle 在线测试。
我有一个 table 用于记录事件。具体有两种类型:ON 和 OFF。
有时会有重叠的日志条目,因为可以同时记录 2 个设备。这并不重要,因为最终报告应该 [大部分] 正确概述开启 -> 关闭期间。
下面是一个示例,第三列只是为了说明:它不存在。
ActionTaken ID ID_of_next_OFF
Switched ON 1 3
Switched ON 2 6
Switched OFF 3
Switched ON 4 7
Switched ON 5 8
Switched OFF 6
Switched OFF 7
Switched OFF 8
Switched On 9 10
Switched OFF 10
Switched On 11 12
Switched OFF 12
给定前两列,如何计算第三列?
这不起作用:
SELECT actionTaken, Id, LEAD(Id)
OVER (PARTITION BY ActionTaken ORDER BY ID) nextConn
FROM dbo.Events
因为它基于 ID_of_Next 下一个匹配的 actionTaken 值,而不是下一个替代值。
像这样的东西应该会让你到达那里。
下面我使用了 2 个 CTE 来拆分关闭和打开数据,然后为第一次打开第一次关闭提供了一个排名项,然后我使用联合查询来匹配它们
declare @Events table (
ActionTaken nvarchar(25),
ID int
);
insert @Events
values
--ActionTaken ID ID_of_next_OFF
('Switched ON' , 1), -- 3
('Switched ON' , 2),-- 6
('Switched OFF', 3),
('Switched ON' , 4),-- 7
('Switched ON' , 5),-- 8
('Switched OFF', 6),
('Switched OFF', 7),
('Switched OFF', 8),
('Switched On' , 9),-- 10
('Switched OFF', 10),
('Switched On' , 11),-- 12
('Switched OFF', 12);
with onrank as (
select row_number()over(order by id) ranking, * from @Events where ActionTaken like '%ON')
, offrank as (
select row_number()over(order by id) ranking, * from @Events where ActionTaken like '%OFF')
select o.ActionTaken, o.ID, case when o.ranking=f.ranking then cast(f.id as nvarchar(3)) end as Id_next_off
from onrank o inner join offrank f on o.ranking=f.ranking
union
select ActionTaken, ID, '' from offrank
order by o.ID;
你走对了。您只需要 'Switched ON'
部分的 LEFT JOIN
与 'Switched OFF'
部分在相同的行号上。
with Events as (
select 'Switched ON' as ActionTaken, 1 as ID union all -- 3
select 'Switched ON', 2 union all -- 6
select 'Switched OFF', 3 union all
select 'Switched ON', 4 union all -- 7
select 'Switched ON', 5 union all -- 8
select 'Switched OFF', 6 union all
select 'Switched OFF', 7 union all
select 'Switched OFF', 8 union all
select 'Switched On', 9 union all -- 10
select 'Switched OFF', 10 union all
select 'Switched On', 11 union all -- 12
select 'Switched OFF', 12
), E as (
select
*, row_number() over(partition by ActionTaken order by ID) as rn
from Events
)
select
a.ActionTaken, a.ID, b.ID
from E as a
left join E as b
on a.ActionTaken = 'Switched ON' and
b.ActionTaken = 'Switched OFF' and
a.rn = b.rn
order by a.ID, a.ActionTaken;
输出:
+--------------+----+------+
| ActionTaken | ID | ID |
+--------------+----+------+
| Switched ON | 1 | 3 |
| Switched ON | 2 | 6 |
| Switched OFF | 3 | NULL |
| Switched ON | 4 | 7 |
| Switched ON | 5 | 8 |
| Switched OFF | 6 | NULL |
| Switched OFF | 7 | NULL |
| Switched OFF | 8 | NULL |
| Switched On | 9 | 10 |
| Switched OFF | 10 | NULL |
| Switched On | 11 | 12 |
| Switched OFF | 12 | NULL |
+--------------+----+------+
使用 SQL Fiddle 在线测试。