Найти следующую запись, где поле состояния отличается от текущего - PullRequest
1 голос
/ 03 июля 2019

У меня есть таблица, которая используется для регистрации событий. В частности, два типа: ВКЛ и ВЫКЛ.

Иногда в журнале могут присутствовать перекрывающиеся записи, поскольку может быть одновременно зарегистрировано 2 устройства. Это не критично, так как в окончательном отчете должен быть [в основном] правильный обзор периодов ВКЛ -> ВЫКЛ.

Ниже приведен пример с 3-й колонкой только для иллюстрации: Не существует.

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 ]

1 голос
/ 03 июля 2019

Вы на правильном пути.Все, что вам нужно, это LEFT JOIN детали 'Switched ON' с деталью '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 .

1 голос
/ 03 июля 2019

что-то вроде этого должно привести вас туда.

Ниже я использовал 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;

enter image description here

...