Последние N событий Тип «2» перед событиями Тип «1» для той же машины - PullRequest
1 голос
/ 16 июня 2020

У меня есть длинный список событий (миллионы), отправленных с разных машин.

Мне нужно получить последние N событий типа «2», которые произошли до того, как события типа «1» на той же машине

Я нашел решение для N = 1, но Я не могу найти решение для N событий

Это мое решение для N = 1:

DECLARE @T AS TABLE
(
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [CodeEvent] [int] NOT NULL,
    [DateTime] [datetime2](7) NULL,
    [Mach] [varchar](max) NULL
) 

INSERT @T VALUES
(2,'12:35:28','M2'),
(1,'12:35:21','M3'),
(4,'12:34:54','M3'),
(8,'12:34:35','M2'),
(2,'12:33:28','M2'),
(2,'12:33:21','M3'),
(1,'12:32:54','M1'),
(8,'12:32:35','M2'),
(1,'12:32:28','M2'),
(2,'12:32:25','M1'),
(1,'12:32:23','M3'),
(3,'12:32:21','M2'),
(2,'12:31:28','M2'),
(2,'12:31:21','M1'),
(4,'12:30:54','M3'),
(8,'12:30:35','M2'),
(1,'12:30:28','M2'),
(2,'12:30:25','M1'),
(2,'12:30:23','M3'),
(2,'12:30:21','M2'),
(1,'12:30:20','M3')

SELECT * FROM @T ORDER BY DateTime Desc;

WITH 
---- T1 All Events
T1 AS (SELECT TOP 100 * 
       FROM @T
       ORDER BY DateTime desc) 
,

---- T2 Events '1'
T2 AS (SELECT TOP 100 * 
       FROM T1 AS T
       WHERE (T.[CodeEvent] = 1)
       ORDER BY DateTime desc ) 
,

---- T4 Last Events type '2' Before type '1' same Mach
T4 AS   
    (select 
    T.ID,
    T.DateTime,
    T.[CodeEvent],
    T.[Mach],
    (SELECT  Top 1 T1.ID
        FROM T1 
        WHERE ((T1.Datetime < T.Datetime) 
           AND (T1.[Mach]=T.[Mach])
           AND (T1.CodeEvent=2))
        ORDER BY T1.DateTime desc) AS LAST_EVENT_ID
    FROM T2 AS T)
,
    
--- T6 get Event from ID
T6 AS (SELECT  
       T.[ID]
      ,T.[CodeEvent]
      ,T.[DateTime]
      ,T.[Mach]
       FROM T4 JOIN T1 AS T
       ON (T4.LAST_EVENT_ID = T.ID)) 


SELECT * FROM T2
UNION ALL
SELECT * FROM T6
ORDER BY [Mach],DateTime Desc

Это то, что я получаю для N = 1

1   1900-01-01 12:32:54.0000000 M1
2   1900-01-01 12:32:25.0000000 M1

1   1900-01-01 12:32:28.0000000 M2
2   1900-01-01 12:31:28.0000000 M2

1   1900-01-01 12:30:28.0000000 M2
2   1900-01-01 12:30:21.0000000 M2

1   1900-01-01 12:35:21.0000000 M3
2   1900-01-01 12:33:21.0000000 M3

1   1900-01-01 12:32:23.0000000 M3
2   1900-01-01 12:30:23.0000000 M3

Это то, что я хотел бы получить для N = 2

1   1900-01-01 12:32:54.0000000 M1
2   1900-01-01 12:32:25.0000000 M1
2   1900-01-01 12:31:21.0000000 M1

1   1900-01-01 12:32:28.0000000 M2
2   1900-01-01 12:31:28.0000000 M2
2   1900-01-01 12:30:33.0000000 M2

1   1900-01-01 12:35:21.0000000 M3
2   1900-01-01 12:33:21.0000000 M3
2   1900-01-01 12:30:23.0000000 M3

1 Ответ

1 голос
/ 16 июня 2020

Я понимаю как проблему с зазорами и островками. Для каждой машины вы хотите сохранить все события «1» и N предшествующие события «2».

Подход состоит в том, чтобы определить группы с суммой окон, которая увеличивается для каждой «1» мероприятие. Затем вы можете перечислить записи в группах с помощью row_number() и отфильтровать.

Это отвечает на вопрос для N = 2.

select CodeEvent, DateTime, Mech
from (
    select
        t.*,
        row_number() over(partition by Mach, grp order by DateTime desc) rn
    from (
        select 
            t.*,
            sum(case when CodeEvent = 1 then 1 else 0 end) over(partition by Mach order by DateTime desc) grp
        from @T t
        where CodeEvent in (1, 2)   
    ) t
) t
where rn <= 3
order by DateTime

Вы управляете N, настраивая последний фильтр на rn.

...